2016-06-10 48 views
6

我對鳳凰/ Elixir非常陌生,我試圖圍繞變化套裝進行探索。如何在將其插入回購之前修改Ecto變更集?

我明白它包含一組用於創建或更新模型的更改。

我想知道的是如何在將數據推送到數據庫之前修改更改。

我的使用情況如下:

  • 我有一個表格,讓人們在數據庫中創建新的藝術家。
  • 在這種形式中有一個專業領域。
  • 創建藝術家之前,我想通過拆分專業領域「」將其存儲爲字符串

數組我什至不知道通過直接修改變更這是可行的,由於不可改變的限制但我也許可以創建另一個變更集以插入回購。

任何建議是值得歡迎的,不要猶豫,指出我可能做的壞行爲或愚蠢的事情!

編輯如下評論: 我看是這樣的:

defp put_specialty_array(changeset) do 
    case changeset do 
    %Ecto.Changeset{valid?: true, changes: %{specialty: spec}} -> 
     put_change(changeset, :specialty, String.split(spec, ",")) 
    _ -> 
     changeset 
    end 
end 
+0

這是散列和存儲用戶密碼的類似方法。檢查[「Phoenix編程」](https://pragprog.com/book/phoenix/programming-phoenix)如何[在此](https://media.pragprog.com/titles/phoenix/code/authentication/listings /rumbl/web/models/user.change1.ex)。 (具體怎麼'registration_changeset'被調用'put_pass_hash') – AbM

+0

這樣我就可以這樣做: defp put_specialty_array(變更)做 情況下變更做 %Ecto.Changeset {有效?:真,變化:%{特長:規範}} - > put_change(changeset,:speciality,String.split(spec,「,」)) changeset end end ? – Cratein

+0

修正了你的建議 – AbM

回答

9

我相信你正在尋找的是一個自定義Ecto.Type。我一直這樣做,而且效果很好!這將是這個樣子:

defmodule MyApp.Tags do 
    @behaviour Ecto.Type 
    def type, do: {:array, :string} 
    def cast(nil), do: {:ok, nil} # if nil is valid to you 
    def cast(arr) when is_list(arr) do 
    if Enum.all?(arr, &String.valid?/1), do: {:ok, arr}, else: :error 
    end 
    def cast(str) when is_binary(str), do: {:ok, String.split(",")} 
    def cast(_), do: :error 

    def dump(val) when is_list(val), do: {:ok, val} 
    def dump(_), do: :error 
    def load(val) when is_list(val), do: {:ok, val} 
    def load(_), do: :error 
end 

然後在你的遷移,添加一列用正確的類型

add :tags, {:array, :string} 

最後在模式中指定您創建的字段類型。

field :tags, MyApp.Tags 

然後,您可以將其作爲字段添加到您的變更集中。如果您的類型轉換返回:error,那麼更改集將會出現類似{:tags, ["is invalid"]}的錯誤。那麼您不必擔心模型或控制器中的字段處理。如果用戶發佈該值的字符串數組或逗號分隔的字符串,它將工作。

如果您需要保存不同格式的值到數據庫中,你只需要改變的def type返回值,並確保def dump返回類型的值,並且def load可以讀取該類型的一個值什麼內部表達你想要的。一種常見的模式是爲內部表示定義一個結構,這樣你就可以自己實現Poison的to_json甚至可以返回一個簡單的字符串。一個例子可能是一個LatLng類型,它在json中編碼爲12.12345N,123.12345W,作爲一些GIS類型存儲在postgres中,但有一個類似%LatLng{lat: 12.12345, lng: -123.12345}的結構,可以讓你在elixir中做一些簡單的數學運算。 DateTime格式的工作方式非常類似(elixir有一個結構,db驅動程序的元組格式和json的ISO格式)。

我認爲這適用於密碼字段,順便說一句。您可以擠壓JSON表示,使用結構來表示算法,算法的參數將鹽與散列分開,或使生活變得簡單。在你的代碼中,要更新密碼,它只是Ecto.Changeset.change(user, password: "changeme")

我意識到這是一個6個月的老問題,你可能已經找到了一些東西,但是我最終從谷歌搜索到了這裏,並假設其他人也會這樣做。

+0

您是否知道是否有辦法將當前用戶的上下文數據注入到自定義字段中? 假設我想使用用戶的密碼短語對字段進行加密/解密並需要從自定義字段中引用密鑰。 –

相關問題