Where to set associations with put_assoc?

Hello folks,

I’m trying to build an application similar to Goodreads, and as such I’ve run into many_to_many relationships, such as an author having multiple books, and a book having multiple offers. I’m beginning to wrap my head around using put_assoc, and I was just wondering if there is a preferred place to actually set the associations. So far I’ve considered putting it into my changeset directly like so

def changeset(book, attrs) do
    required_fields = [:title, :description, :isbn_13, :slug]
    optional_fields = []

    book
    |> cast(attrs, required_fields ++ optional_fields)
    |> validate_required(required_fields)
    |> put_assoc(:authors, attrs.authors)
end

or doing it within the context that I am using to work with all the various objects in the data model.

def create_book(attrs) do
    %Book{}
    |> Book.changeset(attrs)
    |> Ecto.changeset.put_assoc(:authors, attrs.authors)
    |> Repo.insert()
end

Is there any advantage to either approach, or an idiomatic way in Elixir?

Thanks in advance.

2 Likes

The way you’re retrieving the association data suggests that it’s provided by some form filled by an user. So this is untrusted data and you want then to use cast_assoc instead.

Now about the better place to call such an Ecto function I think it depends wether you’ll be always using exclusively your changeset along the said association or wether sometimes you want to use it without that association. In the first case I would just put it in the changeset.

Here some blog post about put_assoc vs cats_assoc.

3 Likes