0

非常に複雑なクエリを作成しようとしていて、問題が発生しています。私が逃しているものを取り除く Active Record AssociationsActive Record Query Interface(具体的にはsection 12 - joins)のRails Guidesを読んでいますが、それらがどのように関連していて、なぜ結合/インクルードが必要なのか分かりません。モデルに関連があるときにRailsで結合/インクルードが必要な理由を理解するのに苦労しています

アソシエーションのページには、「Active Recordアソシエーションを使用すると、宣言的に2つのモデルの間に接続があることをRailsに伝えることで、これらの操作と他の操作を合理化できます。クエリページの12.2節では、「アクティブレコードを使用すると、モデルで定義されている関連付けの名前を、結合メソッドを使用するときにその関連付けにJOIN句を指定するためのショートカットとして使用できます。

これらの2つの文は、私にはお互いに多少の不一致があります。 belongs_toという関連付けを作成すると、なぜ両方のテーブルからデータを取得しようとしている場合に結合が必要なのですか?それを別の方法を探している相手:

class Customer < ActiveRecord::Base 
    has_many :orders 
end 

class Order < ActiveRecord::Base 
    belongs_to :customer 
end 

私は@orders = Order.allをすれば、私は@orders.first.customer.nameを実行して、出力顧客名をすることができます。しかし、名前に「スミス」を含むすべての注文を選択したい場合は、@orders=Order.where('customer.name ilike "%smith%"').joins(:customer)

この「関係」は前半にどのように働いていますが、後半に参加する必要がありますか?

答えて

1

参加する必要はありませんが、アソシエーションに電話するまではデータは読み込まれません。

これはレイジーローディングと呼ばれるActiveRecord::Baseの品質です。

これはコンソールからのSQL出力で確認できます。

user = User.find(1) 
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 

この特定のユーザーモデルは、hundread関連を超えています。

なぜロードされていないのですか?

まだ呼び出されていないためです。

user.articles 
Article Load (0.3ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 1 

ここで、クエリが実行されていることがわかります。

これは、古いRubyで作業するときに問題になります。例えば

、次の点を考慮してくださいユーザーを超えるRubyは反復するたびに、それはそのユーザーに対してのみの記事を呼び出すので、次のコードを実行

users.each do |user| 
    puts user.articles.first.title 
end 

は、問題があります。

次のSQLを実行し、繰り返しユーザーごとに照会終わる:我々は、単一のクエリ内で、最初は私たちのすべてのデータをロードすることによってこの問題を解決することができます

Article Load (0.5ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 1 LIMIT 1 
Article Load (0.5ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 2 LIMIT 1 
Article Load (0.5ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 3 LIMIT 1 
Article Load (0.5ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 4 LIMIT 1 
Article Load (0.5ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 5 LIMIT 1 
Article Load (0.5ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` = 6 LIMIT 1 
etc. 

。列挙が始まる前に、次のSQLを実行します

users.joins(:articles).each do |user| 
    puts user.articles.first.title 
end 

Article Load (0.5ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` IN(1, 2, 3, 4, 5, 6, etc.) 

includesjoinsなどのActiveRecord::Base方法が遊びに来る場所です。

http://blog.arkency.com/2013/12/rails4-preloading/

https://rubyinrails.com/2014/01/08/what-is-lazy-loading-in-rails/

+0

偉大説明:

ここで問題に2件の良い記事があります!あなたは本当に私のためにギャップを埋めるのを助けました。また、その最初の記事は本当に私の新しい情報を与えました - 私はすべての関係をどのようにミックスして一致させるか理解できませんでした。うまくいけば、これは私の質問を元に戻すのに役立ち、私が探している結果を得ることができます。 :) – Ben

+0

は、遅延読み込みの問題 'select.preload(articles).last'と' select.last.preload(articles) 'の順序は同じですか? – Ben

+0

はい、事前ロードはスコープ設定されたセクションでのみ可能です。例えば、 'User.joins(:articles).each'のようにします。スコープから直接ロードする必要があります。それ以外の場合は、おそらく未定義で失敗します。 – fbelanger

関連する問題