Wierzę, czego szukasz jest zwyczaj Ecto.Type. Robię to cały czas i działa świetnie! Byłoby to wyglądać mniej więcej tak:
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
Następnie w swojej migracji, dodaj kolumnę z prawej Typ
add :tags, {:array, :string}
Wreszcie w schemacie określić typ pola, który został utworzony.
field :tags, MyApp.Tags
Następnie możesz po prostu dodać go jako pole w swoim zestawie zmian. Jeśli odlew Twojego typu zwróci :error
, to zestaw zmian będzie miał błąd podobny do {:tags, ["is invalid"]}
. Nie musisz się wtedy martwić o jakiekolwiek przetwarzanie pola w swoim modelu lub kontrolerze. Jeśli użytkownik napisze tablicę ciągów dla wartości lub po prostu ciąg znaków oddzielonych przecinkami, będzie działał.
Jeśli trzeba zapisać wartość do bazy danych w innym formacie, należy po prostu zmienić wartość zwracaną def type
i upewnić się, że def dump
zwraca wartość tego rodzaju i że def load
można odczytać wartość tego typu na cokolwiek reprezentacja wewnętrzna, którą chcesz. Jednym wspólnym schematem jest zdefiniowanie struktury wewnętrznej reprezentacji, aby można było wprowadzić własną implementację Poison's to_json
, która mogłaby nawet zwrócić prosty ciąg znaków. Jednym z przykładów może być typ LatLng, który koduje do 12.12345N,123.12345W
w jsonie, jako niektóre typy GIS w postgresie, ale ma strukturę podobną do %LatLng{lat: 12.12345, lng: -123.12345}
, która pozwala ci wykonać prostą matematykę w eliksiru. Formaty DateTime działają bardzo podobnie (jest tam struktura dla eliksiru, format tupu dla sterownika db i format ISO dla json).
Myślę, że to działa bardzo dobrze dla pól hasła, btw.Możesz zgnieść reprezentację JSON, użyć struktury do reprezentowania algorytmu, parametry do algorytmu oddzielić sól od hash lub cokolwiek innego ułatwia życie. W twoim kodzie, aby zaktualizować hasło, będzie to po prostu Ecto.Changeset.change(user, password: "changeme")
.
Zdaję sobie sprawę, że jest to stare pytanie o długości 6 milionów i prawdopodobnie coś znalazłeś, ale znalazłem się tutaj z wyszukiwarki Google i zakładam, że inni też.
Jest to podobne podejście do haszowania i przechowywania hasła użytkownika. Sprawdź, jak ["Programowanie Phoenix"] (https://pragprog.com/book/phoenix/programming-phoenix) zrobił to [tutaj] (https://media.pragprog.com/titles/phoenix/code/authentication/listings /rumbl/web/models/user.change1.ex). (Konkretnie jak 'registration_changeset' dzwoni' put_pass_hash') – AbM
abym mógł zrobić coś takiego: defp put_specialty_array (changeset) zrobić sprawę changeset zrobić % Ecto.Changeset {poprawne ?: prawdziwe zmiany:% {specjalność: specyfikacji }} -> put_change (zestaw zmian,: specjalizacja, String.split (spec, ",")) zestaw zmian koniec koniec ? – Cratein
Naprawiono sugestię nieco – AbM