Justinbenfit23

Justinbenfit23

Putting Associations with many_to_many relationships

I am trying to build a sales territory table based off of a combination of states. I believe this constitutes a many_to_many relationship if I am trying to build associations between the territories and the states tables in my database. I am trying to work through the Ecto many_to_many associations section found here. However after several attempts at putting my own associations within the contexts of my territories and states tables I kept getting this error:

** (RuntimeError) attempting to cast or change association `tags` from `Gimli.Prospector.Assignment.AssociationTest.Post` that was not loaded. Please preload your associations before manipulating them through changesets (ecto 3.4.6) lib/ecto/changeset/relation.ex:80: Ecto.Changeset.Relation.load!/2 (ecto 3.4.6) lib/ecto/changeset.ex:1199: Ecto.Changeset.put_change/7 (ecto 3.4.6) lib/ecto/changeset.ex:1409: Ecto.Changeset.put_relation/5

As a way of troubleshooting I tried building a posts and a tags table and duplicating the code exactly as it appears in the many_to_many docs and it still gives the same error which leads me to think something might have been deprecated that I don’t know about. I am running elixir 1.11.3.

For quick reference here are the migrations for the posts and tags tables:

  use Ecto.Migration

  def change do
    create table(:posts) do
      add :header, :string
      add :body, :string
    end
  end
end```

```defmodule Gimli.Repo.Migrations.CreateTag do
  use Ecto.Migration

  def change do
    create table(:tags) do
      add :name, :string
    end
  end
end```

Here are the schemas for each respectively:

```defmodule Gimli.Prospector.Assignment.AssociationTest.Post do
    use Ecto.Schema

    schema "posts" do
        field :header, :string
        field :body, :string
        
        many_to_many :tags, Gimli.Prospector.Assignment.AssociationTest.Tag, join_through: "post_tags"
    end
end```

```defmodule Gimli.Prospector.Assignment.AssociationTest.Tag do
    use Ecto.Schema

    schema "tags" do
      field :name, :string
      # the following line was added
      many_to_many :posts, Gimli.Prospector.Assignment.AssociationTest.Post, join_through: "posts_tags"
    end
  end```

and here is the migration for the creation of the helper table per the documentation:

```defmodule Gimli.Repo.Migrations.CreatePostsTags do
  use Ecto.Migration

  def change do
    create table(:posts_tags) do
      add :tag_id, references(:tags)
      add :post_id, references(:posts)
    end

    create unique_index(:posts_tags, [:tag_id, :post_id])
  end
end```

and here is the code from the shell (condensed):

```alias Gimli.Prospector.Assignment.AssociationTest.Post
  alias Gimli.Prospector.Assignment.AssociationTest.Tag
  alias alias Gimli.Repo
  clickbait_tag = Repo.insert! %Tag{name: "clickbait"}
  misc_tag = Repo.insert! %Tag{name: "misc"}
  ecto_tag = Repo.insert! %Tag{name: "ecto"}
  post = %Post{header: "Clickbait header", body: "No real content"}
  post = Repo.insert!(post)
  post_changeset = Ecto.Changeset.change(post)
  post_with_tags = Ecto.Changeset.put_assoc(post_changeset, :tags, [clickbait_tag, misc_tag])```

This is the point that the `RuntimeError` happens. Again this is just copied line for line from the Ecto docs. Any help figuring this out would be very appreciated! Thanks!

Most Liked

stefanchrobot

stefanchrobot

Seems you have a typo here:

many_to_many :tags, Gimli.Prospector.Assignment.AssociationTest.Tag, join_through: "post_tags"

Should be "posts_tags". On to the actual question: the error is giving you the right solution - you need to preload the tags for the post, otherwise Ecto won’t know what to do with the tags that you’re trying to set on the post (insert them? update them? delete old ones?):

post = Repo.insert!(post)
post = Repo.preload(post, :tags)
# now Ecto knows the current tags and will diff them with what you're providing

See the docs for many_to_many/3, it has the preloading in the example. Same thing in the put_assoc/4 docs.

Justinbenfit23

Justinbenfit23

Thank you! I was misunderstanding the definition of the preload function! It worked!

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement