Search code examples
elixirphoenix-frameworkecto

How to change Ecto relationships


I'm a new in Elixir and looking for proper way of how to chanage relationship in Ecto model.

Assume I have model with relationship:

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

And query with preload:

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

Get map %PhoenixApp.Topic{...} with list field topic_meta

I want change value in one of topic_meta fields:

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

Question:

How to insert changed topic_meta relation filed to topic from my query? Make a new query for updating fields looks like unnecessary.

Update in details:

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

Solution

  • If you have your changed_meta in shape you want to update, you should use Repo.update/2:

    Repo.update(changed_meta)
    

    Hope that helps!

    Update

    If you want to see element updated in your topic without reloading it, you could replace current list of topic_meta manually.

    Given you have prepared change_meta, you could do something like:

    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}
    

    With this, the topic from the last line will have updated list of topic_meta, containing the one of changed_meta.