Adding many to the many side of a one-to-many association

I’m still wrapping my mind around this, and it’s the end of the week so I’m starting with a big disclaimer here that I may be missing something obvious.

I have an Article schema and it has many :revisions, schema Revision.

Periodically I am polling an API to pull in any new revisions that may have been created on a 3rd party site. Should there be new revisions I am formatting them into a list of maps with keys and values that match the Revision schema.

I now want to (idiomatically) persist these revisions, relating them to the appropriate article.

This is what I have

article = Repo.get(Article, article_id)
revisions = <call to api module>

result_of_revisions_insert =
  revisions
  |> Enum.map(fn revision ->
        Revision.changeset(%Revision{}, revision)
        |> Ecto.Changeset.put_change(:article_id, article.id)
        |> Repo.insert()
  end)

This is inserting valid revisions (the api doesn’t always provide me with valid data, and I discard what’s invalid later) and returning me a list with the results of each operation. So that’s all good, but is there a better or more idiomatic way to perform this task?

Thanks in advance

I don’t think its common to call put_change like this. An alternative would be to put the article_id into revision before passing it to the changeset e.g. revision = Map.put(revision, :article_id, article_id). You don’t need to load Article, at least in this snippet here.

Thanks for the response. That got me thinking, and I believe I should be using Ecto.build_assoc to build the revision with an article_id

result_of_revisions_insert =
  revisions
  |> Enum.map(fn revision ->
        Ecto.build_assoc(article, :revisions, revision)
        |> Revision.changeset()
        |> Repo.insert()
  end)

Gets me the same result.

Yes, I have to admit I’ve overlooked that for quite awhile now - that does the same thing but much more idiomatic I’m sure.