【问题标题】:rails 3 has_many through has_onerails 3 has_many 到 has_one
【发布时间】:2012-09-18 08:14:49
【问题描述】:

假设您有以下模型:

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

令人惊讶的是,当我调用 Category.first.scores ActiveRecord 时会产生以下查询:

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

上述查询忽略了 Category#current_heat 的 has_one 特性。我本来期望的更像是:

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

仅当您使用 Category.first.current_heat.scores 从根显式遍历 has_one 关联时才会生成。

好像 ActiveRecord 默默地将我的 has_one 视为 has_many。有人可以向我解释这种行为吗?有没有优雅的解决方法或“正确的方法”?

【问题讨论】:

    标签: ruby-on-rails activerecord has-many-through


    【解决方案1】:

    也许你可以删除

    has_many :scores, :through => :current_heat
    

    而只是通过 has_one: 委托 :scores:

    delegate :scores, :to => :current_heat
    

    这将保留您所需的访问方法 Category.first.scores。

    【讨论】:

      【解决方案2】:

      has_one 并不真正存在以这种方式保护您的数据库。如果有多个记录与 foreign_key 匹配,它不会抛出错误,它只会选择第一个。它假定您没有错误地添加额外的记录,这些记录会自行破坏has_one 关系。

      总之,只要Category只有一条记录,它生成的sql就可以了。如果您以某种方式添加了不应该存在的额外记录,因为它是 has_one,那么它将不起作用,但告诉您这已经发生不是 activerecord 的工作。

      【讨论】:

      • 在预赛中每个类别肯定会有不止一行,但没关系,因为我在热火中添加了default_scope order('created_at DESC') 以确保任何时候我在谈论热火时都有一种独特的感觉,这是最近的高温。这样,我就可以灵活地谈论当前和历史上的预赛。所以从某种意义上说,它同时具有 has_many 和 has_one,具体取决于用例。
      猜你喜欢
      • 1970-01-01
      • 2018-04-08
      • 1970-01-01
      • 2012-11-11
      • 1970-01-01
      • 2019-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多