Ich glaube, für das, was Sie suchen eine benutzerdefinierte Ecto.Type ist. Ich mache das die ganze Zeit, und es funktioniert super! Es würde wie folgt aussehen:
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
Dann in der Migration, fügen Sie eine Spalte mit der richtigen Art
add :tags, {:array, :string}
schließlich in Ihrem Schema den Feldtyp angeben, die Sie erstellt haben.
field :tags, MyApp.Tags
Dann können Sie es einfach als ein Feld in Ihrem Changeset hinzufügen. Wenn die Umwandlung Ihres Typs :error
zurückgibt, wird das Änderungsset einen Fehler wie {:tags, ["is invalid"]}
haben. Sie müssen sich dann keine Gedanken über die Verarbeitung des Feldes in Ihrem Modell oder Controller machen. Wenn der Benutzer ein Zeichenfolgenarray für den Wert oder nur eine durch Kommas getrennte Zeichenfolge sendet, funktioniert es.
Wenn Sie den Wert in die Datenbank in einem anderen Format speichern müssen, würden Sie nur den Rückgabewert von def type
ändern und sicherstellen, dass def dump
einen Wert dieses Typs zurückgibt und def load
einen Wert dieses Typs lesen, um was auch immer interne Darstellung, die Sie wollen. Ein übliches Muster ist, eine Struktur für die interne Darstellung zu definieren, so dass Sie Ihre eigene Implementierung von Poisons to_json
machen können, die sogar eine einfache Zeichenkette zurückgeben könnte. Ein Beispiel könnte ein LatLng-Typ sein, der in JSON nach 12.12345N,123.12345W
kodiert, in Postgres als GIS-Typ gespeichert wird, aber über eine Struktur wie %LatLng{lat: 12.12345, lng: -123.12345}
verfügt, mit der man in Elixir einige einfache Berechnungen anstellen kann. Die DateTime-Formate funktionieren ähnlich (es gibt eine Struktur für Elixir, ein Tupel-Format für den DB-Treiber und ein ISO-Format für JSON).
Ich denke, das funktioniert wirklich gut für Passwortfelder, BTW.Sie können die JSON-Darstellung zerquetschen, eine Struktur verwenden, um den Algorithmus darzustellen, Parameter für den Algorithmus getrennt von Hash oder was auch immer das Leben einfacher macht. In Ihrem Code, um ein Passwort zu aktualisieren, wäre es nur Ecto.Changeset.change(user, password: "changeme")
.
Ich weiß, das ist eine 6mo alte Frage, und Sie haben wahrscheinlich etwas gefunden, aber ich bin hier von einer Google-Suche gelandet, und nehme an, andere werden auch.
Dies ist ein ähnlicher Ansatz zum Hashing und Speichern eines Benutzerkennworts. Sehen Sie nach, wie ["Phoenix programmieren"] (https://pragprog.com/book/phoenix/programming-phoenix) es [hier] gemacht hat (https://media.pragprog.com/titles/phoenix/code/authentication/listings) /rumbl/web/models/user.change1.ex). (Genauer gesagt, wie 'registration_changeset' ruft' put_pass_hash') – AbM
So konnte ich so etwas wie: defp put_specialty_array (changeset) tun Fall ChangeSet % Ecto.Changeset tun {gültig ?: wahr, Änderungen:% {Spezialität: spec }} -> put_change (Changeset,: Spezialität, String.split (spec, ",")) changeset Ende Ende ? – Cratein
Korrigiert Ihren Vorschlag ein wenig – AbM