我相信你正在尋找的是一個自定義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個月的老問題,你可能已經找到了一些東西,但是我最終從谷歌搜索到了這裏,並假設其他人也會這樣做。
這是散列和存儲用戶密碼的類似方法。檢查[「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
這樣我就可以這樣做: defp put_specialty_array(變更)做 情況下變更做 %Ecto.Changeset {有效?:真,變化:%{特長:規範}} - > put_change(changeset,:speciality,String.split(spec,「,」)) changeset end end ? – Cratein
修正了你的建議 – AbM