Как изменить отношения Экто

Я новичок в Эликсире и ищу правильный способ изменить отношения в модели Ecto.

Предположим, у меня есть модель с отношениями:

 schema "topic" do
      has_many :topic_meta, PhoenixApp.TopicMeta

И запрос с предварительной загрузкой:

 topic = from t in query,
        left_join: meta in assoc(t, :topic_meta),
        preload: [topic_meta: meta] 
        |> Repo.one

Получить карту %PhoenixApp.Topic{...} со списком topic_meta

Я хочу изменить значение в одном из topic_meta полей:

 changed_meta = %{List.first(topic.topic_meta) | last_read: "newValue"}

Вопрос:

Как вставить измененное отношение topic_meta к topic из моего запроса? Сделать так, чтобы новый запрос на обновление полей выглядел ненужным.

Обновите подробную информацию:

first_meta = List.first(topic.topic_meta) // this is first meta

result =  Repo.update!(PhoenixApp.Topic.changeset(first_meta, %{last_read: "newValue"}))

case result do
  {:ok, topic_meta}        ->  
 // topic_meta successfully updated, but topic does not contain this model
end

person user1156168    schedule 12.04.2016    source источник


Ответы (2)


Если ваш changed_meta в форме, которую вы хотите обновить, вам следует использовать Repo.update/2 < / а>:

Repo.update(changed_meta)

Надеюсь, это поможет!

Обновить

Если вы хотите, чтобы элемент был обновлен в вашем topic, не перезагружая его, вы можете заменить текущий список topic_meta вручную.

Если вы подготовили change_meta, вы можете сделать что-то вроде:

index = Enum.find_index(topic.topic_meta &(&1.id == changed_meta.id))
list  = List.replace_at(topic.topic_meta, index, changed_meta)
topic = %{topic | topic_meta: list}

При этом topic из последней строки будет иметь обновленный список topic_meta, содержащий один из changed_meta.

person Paweł Dawczak    schedule 13.04.2016
comment
Спасибо за Ваш ответ. Подробно подробно изложил вопрос в разделе «Обновление в деталях». Вопрос был в том, как объединить Repo.update результат с исходными данными. - person user1156168; 13.04.2016
comment
Ой! Я понимаю, о чем вы спрашиваете. Боюсь, что нет простого способа сделать это из-за неизменности. topic не похож на объекты (например, в Ruby / Java), поэтому такое изменение не отражается сразу. Самый простой способ отразить это - просто перезагрузить данные из базы данных. Здесь разделение действий в Phoenix имеет смысл - вы обновляете значения в действии update и перенаправляете пользователя на вид действия show, где обновленные данные извлекаются из базы данных. - person Paweł Dawczak; 13.04.2016
comment
Привет, @ user1156168 - взгляни, пожалуйста, на обновленный ответ. Код довольно подробный (по сравнению с тем, что у вас было бы, если бы вы сделали то же самое на языке OO), но он должен делать то, что вы ожидаете. Надеюсь, это немного проясняет проблему! - person Paweł Dawczak; 13.04.2016