4

A、B、C、Dの4つのモデルがあります

class A < ActiveRecord::Base
  has_many :B
  has_many :C, :through => :B
end  

class B < ActiveRecord::Base
  belongs_to :A  
  has_many   :C
  has_many   :D, :through => :C
end  

class C < ActiveRecord::Base    
  belongs_to :B
end    

class D < ActiveRecord::Base    
  belongs_to :C
end    

私は非常に素朴な実装を持っていますが、それは非常に明白です...

<% A.B.each do |b| %>
  <%= b.number %>
  <% b.C.each do |c| %>
    <%= c.name %>
  <% end %>
<% end %>

All C for Aを入手するための最良の方法は何ですか?All D for Aを入手する最良の方法は何ですか?

Bを反復処理する代わりに、「created_at」値を持つorder_by句を使用してすべての「C」を取得したいと思います。

ActiveRecordの魔法が欠けているのではないでしょうか?

助けていただければ幸いです。

4

1 に答える 1

6

まず、いくつかの変更を加える必要があります。

  1. class Cに関連付ける必要がありますD

    class C < ActiveRecord::Base
      belongs_to :B
      has_one :D
    end
    
  2. A's 'にアクセスする場合はD、これも指定する必要があります。

    class A < ActiveRecord::Base
      has_many :B
      has_many :C, :through => :B
      has_many :D, :through => :C
    end
    

Aここで、すべての's 'にアクセスするにはC

-> a = A.where(:id => 1).includes(:C).first
  A Load (0.2ms)  SELECT "as".* FROM "as" WHERE "as"."id" = 1 LIMIT 1
  B Load (0.1ms)  SELECT "bs".* FROM "bs" WHERE "bs"."a_id" IN (1)
  C Load (0.1ms)  SELECT "cs".* FROM "cs" WHERE "cs"."b_id" IN (1, 2)
 => #<A id: 1, created_at: "2012-01-10 04:28:42", updated_at: "2012-01-10 04:28:42"> 
-> a.C
 => [#<C id: 1, b_id: 1, created_at: "2012-01-10 04:30:10", updated_at: "2012-01-10 04:30:10">, #<C id: 2, b_id: 1, created_at: "2012-01-10 04:30:11", updated_at: "2012-01-10 04:30:11">, #<C id: 3, b_id: 2, created_at: "2012-01-10 04:30:21", updated_at: "2012-01-10 04:30:21">, #<C id: 4, b_id: 2, created_at: "2012-01-10 04:30:21", updated_at: "2012-01-10 04:30:21">]

を呼び出したときに別のクエリが実行されないことに注意してくださいa.C。これは、ActiveRecordが、呼び出しによって見つかったにアクセスする必要があることを認識してAおり、最小数のクエリを生成するためですCinclude同じことがD'sにも当てはまります:

-> a = A.where(:id => 1).includes(:D).first
  A Load (0.1ms)  SELECT "as".* FROM "as" WHERE "as"."id" = 1 LIMIT 1
  B Load (0.1ms)  SELECT "bs".* FROM "bs" WHERE "bs"."a_id" IN (1)
  C Load (0.1ms)  SELECT "cs".* FROM "cs" WHERE "cs"."b_id" IN (1, 2)
  D Load (0.1ms)  SELECT "ds".* FROM "ds" WHERE "ds"."c_id" IN (1, 2, 3, 4)

Aすべての's D'が必要だったが、C'sが注文されたとしましょう。

A.where(:id => 1).includes(:C).order('cs.created_at DESC').includes(:D)

これをアソシエーションのデフォルトとして設定することもできることに注意してください。

この:orderオプションは、関連するオブジェクトを受け取る順序を指定します(SQLORDER BY句で使用される構文で)。

class Customer < ActiveRecord::Base
  has_many :orders, :order => "date_confirmed DESC"
end
于 2012-01-10T04:45:04.093 に答える