Search code examples
elixirecto

How do I use a has_one to refer to non primary key column? Elixir


I have a table

  @primary_key false
  schema "user_reward_entries" do
    field(:id, Ecto.UUID, primary_key: true, read_after_writes: true)
    field(:amount, :integer)
    ...

    belongs_to(:transaction, Transaction)
    belongs_to(:user, User)

    timestamps()
  end

This table has a complex primary key made up of the id and the user_id. I am referring to the transactions table with the belongs_to.

In the transaction table I am trying to refer back to the transaction table.

  @primary_key false
  schema "accounts_transactions" do
    field(:id, Ecto.UUID, primary_key: true, read_after_writes: true)

    ...

    has_one :user_reward_entry, UserRewardEntry

    field(:completed_at, :utc_datetime_usec)

    timestamps()
  end

The error I get is need to set :references option for association :user_reward_entry when schema has no primary key. I then tried to use the references option, like this

    has_one :user_reward_entry, UserRewardEntry,
      references: UserRewardEntry,
      foreign_key: :transaction_id

and get another error schema does not have the field SharedDb.Models.Rewards.UserRewardEntry used by association :user_reward_entry, please set the :references option accordingly.

I have also tried

    has_one :user_reward_entry, UserRewardEntry,
      references: UserRewardEntry,
      foreign_key: :transaction

and get the same error.

I obviously don't understand what I need to do here. What am I missing?


Solution

  • As it is stated in the documentation for has_one/3

    • :foreign_key - Sets the foreign key, this should map to a field on the other schema, defaults to the underscored name of the current module suffixed by _id
    • :references - Sets the key on the current schema to be used for the association, defaults to the primary key on the schema

    You don’t need to ever touch neither references (which expects a field btw, not a module) nor foreign_key, but the association name belongs_to in reward_entries. It currently mentions unknown to Transaction.

    That said, the following should work (actually, foreign_key: :transaction_id might be also needed):

    belongs_to :transaction, {"accounts_transactions", Transaction}