a.barbieri a.barbieri - 1 year ago 58
Ruby Question

Get unexpected result from has_one relationship

I have a

Selection
model which has many
Choices
and one
DefaultChoice
.
The relation is structured this way.

Models (I think here there is something wrong)


class Selection < ApplicationRecord
has_many :choices, dependent: :delete_all
has_one :default_choice, class_name: 'Choice'
end

class Choice < ApplicationRecord
belongs_to Selection
end


Migration


create_table :selections do |t|
t.references :default_choice, index: true
end
create_table :choices do |t|
t.belongs_to :selection
end


Somehow something is not right:



# let's say:
selection = Selection.find(1)
selection.choices << Choice.find(1)
selection.choices << Choice.find(2)
selection.default_choice = Choice.find(2)
selection.save!

# then
selection.default_choice_id = 2
# but
selection.default_choice.id = 1


How come?!

selection.default_choice
generates this query:

Choice Load (0.5ms) SELECT "choices".* FROM "choices" WHERE "choices"."selection_id" = $1 LIMIT $2 [["selection_id", 1], ["LIMIT", 1]]

Answer Source

You're using the same model Choice for both relationships has_many :choiches and has_one :default_choice. So when you query has_one :default_choice result are all from choices table and with has_one you only get one result which is the first it finds referenced to Selection object.


UPDATE

To implement default on has_many you can do something like add column on Choice model that will be true if it's default choice. Then has_one relationship would need to have scope to get only choice that is default true like this:

has_one :default_choice, -> { where default_choice: true }, class_name: 'Choice'
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download