Duplicating entries with associations in elixir

My blog app has a feature that allows people to make copies of other people’s posts, and host them as their own.

Posts are associated with owners.

  schema "posts" do 
    field :title, :string 
    field :content, :string 

    belongs_to :owner, MyApp.Accounts.User, foreign_key: :owner_id
  end 

I would like to get a copy of a Post by id, remove the id and owner_id fields, cast the new owner id, and then insert.

resolve fn (%{post_id: post_id, new_owner_id: new_owner_id}, _info) ->
  Repo.get!(Post, post_id)
    |> Map.delete(:id)
    |> Map.delete(:owner_id)
    |> Post.changeset(%{owner_id: new_owner_id})
    |> Repo.insert!
end

But when I do, I get this error:

Request: POST /api
** (exit) an exception was raised:
    ** (RuntimeError) attempting to cast or change association `owner` from `MyApp.Content.List` that was not loaded. Please preload your associations before manipulating them through changesets

What is the correct way to do this copy?

I would rather create a new post from an old one…

post = Repo.get!(Post, post_id)
Post.changeset(%{title: post.title, content: post.content, owner_id: new_owner_id})
|> Repo.insert!

That said, I would prefer to create resolvers in a lib/resolvers folder, and use contexts instead of exposing Repo. Even if most of the functions would just be delegation. That would clean up your schema.

The error message tells You You did not load assoc, You might miss…

|> Repo.preload(:owner)

… in your pipeline

2 Likes

I prefer the first approach, thanks :slight_smile:

I started with lib/resolvers (as seems to be convention), but lately I’ve been inlining the resolvers. It’s just easier to read. Same with contexts; I use them occasionally (when there is a specific thing I want to do), but I don’t see the problem with exposing the Repo. Any reasons for the convention?

No, just personal taste :slight_smile: When I read my contexts, I read my public api

1 Like