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
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
Thank you! I was misunderstanding the definition of the preload function! It worked!
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









