Как обновить ассоциацию «многие ко многим» с помощью Ecto

#elixir #associations #phoenix-framework

#elixir #ассоциации #phoenix-framework

Вопрос:

У меня есть приложение Phoenix с двумя ресурсами, которые имеют отношение «многие ко многим». Для упрощения давайте назовем их posts и tags. Когда я создаю сообщение с нуля, я могу связать с ним существующие теги. Я также могу отредактировать сообщение, в котором нет тегов, чтобы связать с ним теги. Однако всякий раз, когда я хочу отредактировать, какие теги связаны с сообщением, я получаю эту ошибку:

 you are attempting to change relation :tags of MyApp.Posts.Post but the `:on_replace` option of
this relation is set to `:raise`
  

Вот мой набор изменений — я использую put_assoc , который имеет 4 аргумента, но, согласно документам, параметр opts не используется, поэтому я не могу установить параметр on_replace:

 def changeset(%__MODULE__{} = user, attrs) do
    tag_ids = if attrs["tags"], do: attrs["tags"], else: []
    tags = Tags.by_ids(tag_ids)

    user
    |> Repo.preload(:tags)
    |> cast(attrs, [:title, :body])
    |> put_assoc(:tags, tags)
    |> validate_required([:body])
  end
  

Идея состоит в том, чтобы обновлять только ассоциацию между ними — я бы никогда не создавал или не удалял сами теги из формы сообщений. Должен ли я обновлять их по-другому?

Ответ №1:

Проблема здесь в том, что ecto не знает, что делать с вами, напрямую обновляя уже существующую связь между вашим пользователем и тегами, должен ли он удалить все и вставить только новые, должен ли он добавить к существующим?

По умолчанию, как указано в ошибке, это будет :raise ошибка.

Упомянутая в нем опция объявляется в отношении, а не при приведении / размещении ассоциаций, как описано здесь

Чтобы всегда использовать теги, которые добавляются в набор изменений, вам следует добавить этот параметр в отношение

 many_to_many :tags, MyApp.Tag, join_through: "posts_tags", on_replace: :delete
  

Более подробная информация об этой опции здесь

Комментарии:

1. Спасибо! Я думаю, что я был сбит с толку, потому что объяснение в документах было в разделе о cast_assoc и put_assoc.