5
votes

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

1
Also please don't use "changeset.valid?", use case Repo.insert(...) do and pattern match on the results.José Valim
@JoséValim Thank you very much for the tipHaito

1 Answers

6
votes

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