svilen

svilen

Author of Concurrent Data Processing in Elixir

Issue with a `many_to_many` assoc and `join_keys`

I’m trying to set up the usual many-to-many relationship between two schemas: User and Conversation. However, the primary key on the conversations table is uuid rather than id.

What I have so far is the following:

  # conversation.ex
  @primary_key {:uuid, :binary_id, autogenerate: true}
  schema "conversations" do
    many_to_many :users, User,
      join_through: "conversations_users",
      join_keys: [user_id: :id, conversation_uuid: :uuid]
  end
  
  # user.ex
  schema "users" do
    many_to_many :conversations, Conversation,
      join_through: "conversations_users",
      join_keys: [user_id: :id, conversation_uuid: :uuid]
  end

Which makes sense to me, after reading the documentation about join_keys but unfortunately produces the following error on compile:

== Compilation error in file lib/myapp_web/models/conversation.ex ==
** (ArgumentError) schema does not have the field :id used by association :users, please set the :join_keys option accordingly
    lib/ecto/association.ex:959: Ecto.Association.ManyToMany.struct/3
    lib/ecto/schema.ex:1734: Ecto.Schema.association/5
    lib/ecto/schema.ex:1876: Ecto.Schema.__many_to_many__/4
    lib/myapp_web/models/conversation.ex:23: (module)
    (stdlib) erl_eval.erl:677: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

So I’m stuck here and I have a feeling I’m missing something really simple, but I can’t figure out what it is :slight_smile: Any help is appreciated! Thank you!

Edit: forgot to mention version numbers:

{:phoenix, "~> 1.4"},
{:phoenix_ecto, "~> 4.0"},
{:ecto_sql, "~> 3.0"},

Elixir: v1.8

Marked As Solved

al2o3cr

al2o3cr

From the docs for join_keys:

It expects a keyword list with two entries, the first being how the join table should reach the current schema and the second how the join table should reach the associated schema.

Keyword lists are ordered - have you tried flipping the declaration for :users?

  # conversation.ex
  @primary_key {:uuid, :binary_id, autogenerate: true}
  schema "conversations" do
    many_to_many :users, User,
      join_through: "conversations_users",
      join_keys: [conversation_uuid: :uuid, user_id: :id]
  end

Also Liked

svilen

svilen

Author of Concurrent Data Processing in Elixir

Correction! @al2o3cr is totally right, the order does matter, and I wasn’t careful enough when making the changes.

The final solution is:

  # conversation.ex
  @primary_key {:uuid, :binary_id, autogenerate: true}
  schema "conversations" do
    many_to_many :users, User,
      join_through: "conversations_users",
      join_keys: [conversation_uuid: :uuid, user_id: :id]
  end
  
  # user.ex
  schema "users" do
    many_to_many :conversations, Conversation,
      join_through: "conversations_users",
      join_keys: [user_id: :id, conversation_uuid: :uuid]
  end

Notice that for the Conversation, the order is [conversation_uuid: :uuid, user_id: :id] and for the User it is [user_id: :id, conversation_uuid: :uuid]. What I did previously was using the same order for both, which produced the exception again.

I’ll try to find time to open an issue / PR when I get a chance :slight_smile: it will be great to improve the docs in this area. Thanks everyone!

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement