Преобразуйте определенные поля набора изменений в поле ecto: map - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть набор изменений, который выглядит так:

%{
  creator_id: "4",
  name: "a test with GraphQL",
  place_id: "13",
  entree_id: "8",
  base: "wheat",
  type: "food"
}

Моя схема Экто выглядит следующим образом:

schema "items" do
  field :type, :string
  field :name, :string
  field :data, :map

  belongs_to :creator, Name.SubName.Creators
  belongs_to :place,   Name.SubName.Places
  belongs_to :entree,  Name.SubName.Entrees

  timestamps()
end

Как видите, base не является полем, находящимся в экто-схеме, я хочу преобразовать base в поле data, чтобы оно имело тип map, то есть: {"base":"wheat"} , Я использую некоторую форму наследования одной таблицы здесь.

Я пытаюсь добавить запись в мою таблицу items. Прямо сейчас, когда я читаю из таблицы, я преобразую поле data во встроенную схему (в зависимости от type), которая прекрасно содержит мое поле base. Я борюсь за то, чтобы вернуть это поле в базу данных.

Я пытался использовать что-то вроде Ecto.Changeset.cast(params[:base], Map.keys(%{data: :map})), но очевидно, что он просто получает значение, которое явно не является действительной картой. Кроме того, было бы больно указывать для всех уникальных полей, связанных с моими другими встроенными схемами, которые представляют каждую type.

embeds_one и embeds_many не применимы к этой ситуации, поскольку поле data ecto представляет разные типы встроенных схем. Так что в этом случае мой вопрос не столько об использовании встроенной схемы, сколько о выделении определенных полей в changeset и преобразовании их в map. Половина меня просто думает, что я должен составить отдельную таблицу для каждого type, и тогда мне не нужно об этом беспокоиться.

1 Ответ

0 голосов
/ 03 ноября 2018

Вы можете использовать Map.split/2:

@required_fields [:name, :type, :creator_id, :place_id, :entree_id]
@all_fields [:data | @required_fields]

def changeset(struct, params) do
  {allowed, others} = Map.split(params, @required_fields)
  params = Map.put(allowed, :data, others)

  struct
  |> cast(params, @all_fields)
  |> # ...
end

Важно отметить, что этот пример работает только для карт с атомными ключами, вам придется немного его изменить, чтобы он работал как со строковыми, так и с атомными ключами. Вы также можете указать пустую карту в качестве значения по умолчанию для :data.

...