ActiveRecord :has_many 并包含

ActiveRecord :has_many and includes

我正在使用 rails 4.2.0 - 这是我的模型:

class Customer < ApplicationRecord
  has_many :meters, -> { includes :contracts }
end

class Meter < ApplicationRecord
  belongs_to :customer
  has_many :contracts
end

class Contract < ApplicationRecord
  belongs_to :meter
end

现在,我想显示一个客户的所有合同。根据 Rails Guides 我应该可以这样做:

@customer.meters.contracts

然而,它不起作用。这是错误消息:

undefined method `contracts' for #<Meter::ActiveRecord_Associations_CollectionProxy:0x007fb0385730b0>

在这种情况下最好的方法是什么? 感谢您的帮助!

每个模型 class,如您的示例所示,仅代表数据库记录的这些实例之一,即您的 Meter class 仅代表其中的一个 metermeters table。因此,考虑到这一点,您可以看到 meter has_many contracts 的声明意味着每个 meter 实例都有许多 contracts.

让我们将这一行分解:@customer.meters.contracts

你有你的 @customer 实例,你正在请求它的所有计量:@customer.metersmeters 方法的 return 是属于 @customermeters 的 collection。因为是一个meter的实例,有很多合约,所以你不能这样向meter的collection要他们的合约。

您可以向单个仪表询问它:@customer.meters.first.contracts 或者您可以遍历所有仪表并获得所有合同:

@customer.meters.flat_map(&:contracts) # => an array of all the contracts

或者,更一般地说,您可能希望在视图中显示客户合同列表:

<% @customer.meters.each do |meter| %>
  <% meter.contracts.each do |contract|
    // display the contract
  <% end %>
<% end %>

但是,您可以通过 meters 关联将所有 contracts 关联到 customer

class Customer < ApplicationRecord
  has_many :meters, -> { includes :contracts }
  # ActiveRecord's shorthand declaration for associating
  # records through a join table, in this case 'meters'
  has_many :contracts, through: :meters
end

通过添加 has_many X, through: Y,您是说客户记录通过联接 table [=34] 与另一个 table X 中的记录相关联=].

有了这个,给定一个 customer 和现有的 meters 以及那些具有现有 contracts 的仪表,您将能够调用 @customer.contracts 并且 ActiveRecord 将获取contracts 通过加入客户的 meters 和他们的 contracts 和 return contracts collection.

更多关于 Rails 有很多直通协会:http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association