简体   繁体   中英

rails 3 has_many through has_one

Suppose you have the following models:

class Category < ActiveRecord::Base
  has_one :current_heat, class_name: 'Heat'
  has_many :scores, :through => :current_heat
end

class Heat < ActiveRecord::Base
  belongs_to :category
  has_many :scores
end

class Score < ActiveRecord::Base  
  belongs_to :heat
end

Surprisingly, when I invoke Category.first.scores ActiveRecord produces the following queries:

SELECT `categories`.* FROM `categories` LIMIT 1
SELECT * FROM `scores` INNER JOIN `heats` ON `scores`.`heat_id` = `heats`.`id` WHERE `heats`.`category_id` = 1

The above query ignores the has_one nature of Category#current_heat . I would have expected something more like:

SELECT `categories`.* FROM `categories` LIMIT 1
SELECT `heats`.* FROM `heats` WHERE `heats`.`category_id` = 1 LIMIT 1
SELECT * FROM `scores` WHERE `scores`.`heat_id` = 6

which is produced only when you explicitly traverse the has_one association from the root with Category.first.current_heat.scores .

It's as if ActiveRecord is silently treating my has_one as a has_many. Can someone explain this behavior to me? Is there an elegant workaround or a "right way" to do it?

Maybe you could remove the

has_many :scores, :through => :current_heat

and instead just delegate :scores through the has_one:

delegate :scores, :to => :current_heat

that would preserve your desired access method Category.first.scores.

has_one doesn't really exist to babysit your database in this fashion. It won't throw errors if there is more than one record that matches the foreign_key, it will just choose the first one. It assumes you haven't errantly added extra records which would break the has_one relation on your own.

In conclusion, the sql that it generates is fine as long as there is only one record attached to the Category. If somehow you've added extra records which shouldn't exist since it is a has_one , then it won't work, but it's not the job of activerecord to tell you that this has happened.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM