假设我们有以下(尽管很复杂)设置:
class Company < ActiveRecord::Base
has_many :homes, inverse_of: :company
has_many :item_company_items, class_name: 'CompanyItem', inverse_of: :item_company, foreign_key: :item_company_id
has_many :home_company_items, class_name: 'CompanyItem', inverse_of: :home_company, foreign_key: :home_company_id
has_many :replacement_items, through: :item_company_items, source: :replacement_items, inverse_of: :responsible_company
end
class Home < ActiveRecord::Base
belongs_to :company, inverse_of: :homes
has_many :company_items, through: :company, source: :home_company_items, inverse_of: :homes
has_many :replacement_items, inverse_of: :home
end
class CompanyItem < ActiveRecord::Base
belongs_to :item, inverse_of: :company_items
belongs_to :item_company, class_name: 'Company', inverse_of: :item_company_items, foreign_key: :item_company_id
belongs_to :home_company, class_name: 'Company', inverse_of: :home_company_items, foreign_key: :home_company_id
has_many :homes, through: :home_company, source: :homes, inverse_of: :company_items
has_many :replacement_items, -> company_item {
where item_id: company_item.item_id
}, through: :homes, source: :replacement_items, inverse_of: :company_item
end
class Item < ActiveRecord::Base
has_many :replacement_items, inverse_of: :item
has_many :company_items, inverse_of: :item
end
class ReplacementItem < ActiveRecord::Base
belongs_to :item, inverse_of: :replacement_items
belongs_to :home, inverse_of: :replacement_items
has_one :company_item, -> rep { where item_id: rep.item_id }, through: :home, source: :company_items, inverse_of: :replacement_items
has_one :responsible_company, through: :company_item, source: :item_company, inverse_of: :replacement_items
end
因此,实际上,Item
有许多CompanyItem
个代表Company
的{{1}},CompanyItem#item_company
属于ReplacementItem
Item
ReplacementItem
适用于属于Home
(Company
)指定的CompanyItem
的{{1}}。
非常迂回,但它正是我们所需要的。
现在,正如我们所看到的,在CompanyItem#home_company
模型上,ReplacementItem
关系使用范围来选择属于与has_one :company_item, through: :home
匹配的CompanyItem
的特定home
{1}}。当我们真正需要匹配给定item_id
的项目时,只需执行replacement_item.home.company_items
就可以为我们提供所有homes
公司项目。调用ReplacementItem
方法可以完美地运行,并为我们提供我们想要的内容。
同样,ReplacementItem#company_item
模型具有CompanyItem
,使用完全相同的范围来获取与给定has_many :replacement_items, through: :homes
匹配的替换项。但是,在这种情况下,我们在调用CompanyItem
时遇到错误:
CompanyItem#replacement_items
对我来说,这看起来像是一个Rails错误。绝对没有办法将NoMethodError: undefined method `item_id' for #<Company id: 2>
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activemodel/lib/active_model/attribute_methods.rb:434:in `method_missing'
bug.rb:59:in `block in <class:CompanyItem>'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association_scope.rb:161:in `instance_exec'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association_scope.rb:161:in `eval_scope'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association_scope.rb:139:in `block in add_constraints'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association_scope.rb:138:in `each'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association_scope.rb:138:in `add_constraints'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association_scope.rb:28:in `scope'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association_scope.rb:5:in `scope'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association.rb:97:in `association_scope'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/association.rb:86:in `scope'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/collection_association.rb:327:in `scope'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/collection_proxy.rb:36:in `initialize'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/relation/delegation.rb:101:in `new'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/relation/delegation.rb:101:in `create'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/collection_association.rb:46:in `reader'
/Users/cbankester/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/rails-bf5876af099f/activerecord/lib/active_record/associations/builder/association.rb:111:in `replacement_items'
bug.rb:85:in `test_hmt_with_conditions'
对象传递到Company
模型上定义的has_many :replacement_items
范围。不过,在讨论Rails团队之前,我希望有人在这里看到类似的问题,或者可以在我的代码中指出错误。
请参阅我的要点,了解可运行的失败测试:https://gist.github.com/cmbankester/64ef4eb125bf90dbe0274fab8e5427f1