Search code examples
elixirphoenix-frameworkecto

Ecto relations, not inserting foreign key ids


Sup, I'm learning Ecto and I'm trying to insert record with association to another table. It is kinda working, because record is being inserted but foreign key field is empty.

Code:

parent = Repo.get(Hangman.MasterCat, parent_id)
changeset = build(parent, :categories)
  |> Category.changeset( params)
IO.inspect(changeset)

if changeset.valid? do
  Repo.insert(changeset)
  json conn, ResponseUtils.jsonResponse(true)
else
  json conn, ResponseUtils.jsonResponse(false,["parents doesn't exist"])
end

Inspection of changeset

%Ecto.Changeset{action: nil, changes: %{name: "Kategory 1"}, constraints: [],
 errors: [], filters: %{},
 model: %{__meta__: #Ecto.Schema.Metadata<:built>, __struct__: Hangman.Category,

   id: nil, inserted_at: nil, master_cat_id: 1,
   mastercat: #Ecto.Association.NotLoaded<association :mastercat is not loaded>,

   mastercat_id: nil, name: nil, updated_at: nil,
   words: #Ecto.Association.NotLoaded<association :words is not loaded>},
 optional: [], opts: [], params: %{"name" => "Kategory 1"}, repo: nil,
 required: [:name],
 types: %{id: :id, inserted_at: Ecto.DateTime, mastercat_id: :id, name: :string,

   updated_at: Ecto.DateTime,
   words: {:assoc,
    %Ecto.Association.Has{cardinality: :many, defaults: [], field: :words,
     on_cast: :changeset, on_delete: :nothing, on_replace: :raise,
     owner: Hangman.Category, owner_key: :id, queryable: Hangman.Word,
     related: Hangman.Word, related_key: :category_id}}}, valid?: true,
 validations: []}

What I can see is for some weird reason it assigns the parent id to field master_cat_id instead of mastercat_id.

Any help is much appreciated. https://github.com/Hajto/hangmanelixir


Solution

  • The foreign key is inferred from the module name by the association_key/2 function in the (deliberately undocumented) Ecto.Association module:

    iex(1)> Ecto.Association.association_key(User, :id)
    :user_id
    iex(3)> Ecto.Association.association_key(FooBar, :id)           
    :foo_bar_id
    iex(5)> Ecto.Association.association_key(MasterCat, :id)
    :master_cat_id
    

    Change the belongs_to/3 schema to use an explicit foreign key field name:

       schema "categories" do
        field :name, :string
    
        has_many :words, Hangman.Word
        belongs_to :mastercat, Hangman.MasterCat, foreign_key: :master_cat_id
    
        timestamps
      end