Ruby on Railsで関連付けをロードするためのさまざまな方法

Railsは、プリロード、eager_load、インクルード、および結合という4つの異なる関連付けのロード方法を提供します。 それらのそれぞれを考慮してください:



プリロード



このメソッドは、別のリクエストで関連付けをロードします。

User.preload(:posts).to_a # => SELECT "users".* FROM "users" SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1)
      
      





なぜなら プリロードでは常に2つの個別のリクエストが作成されるため、選択条件で投稿テーブルを使用することはできません。

 User.preload(:posts).where("posts.desc='ruby is awesome'") # => SQLite3::SQLException: no such column: posts.desc: SELECT "users".* FROM "users" WHERE (posts.desc='ruby is awesome')
      
      





そして、ユーザーテーブル-私たちは次のことができます:

 User.preload(:posts).where("users.name='Neeraj'") # => SELECT "users".* FROM "users" WHERE (users.name='Neeraj') SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (3)
      
      









含む



デフォルトでは、インクルードはプリロードと同様に機能しますが、関連付けられたテーブルに条件がある場合、LEFT OUTER JOINを使用した単一のクエリの作成に切り替わります。

 User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a # => SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3 FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE (posts.desc = "ruby is awesome")
      
      





何らかの理由でこのアプローチの適用を強制する必要がある場合、referencesメソッドを使用できます。

 User.includes(:posts).references(:posts).to_a # => SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3 FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
      
      







Eager_load



このメソッドは、参照と一緒にインクルードするのと同じように、Left Outer Joinを使用して単一の要求で関連付けをロードします。



 User.eager_load(:posts).to_a # => SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3 FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
      
      







参加する



INNER JOINを使用してクエリを作成します。

 User.joins(:posts) # => SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
      
      





この場合、ユーザーテーブルからデータのみがロードされます。 さらに、このクエリは重複エントリを返す場合があります。

 def self.setup User.delete_all Post.delete_all u = User.create name: 'Neeraj' u.posts.create! title: 'ruby', desc: 'ruby is awesome' u.posts.create! title: 'rails', desc: 'rails is awesome' u.posts.create! title: 'JavaScript', desc: 'JavaScript is awesome' u = User.create name: 'Neil' u.posts.create! title: 'JavaScript', desc: 'Javascript is awesome' u = User.create name: 'Trisha' end
      
      







次のデータを含むデータベースでUser.joins(:posts)を実行した結果:

 #<User id: 9, name: "Neeraj"> #<User id: 9, name: "Neeraj"> #<User id: 9, name: "Neeraj"> #<User id: 10, name: "Neil">
      
      





distinctを使用して繰り返しを回避できます。

 User.joins(:posts).select('distinct users.*').to_a #   ,    : User.joins(:posts).uniq
      
      





postsテーブルから追加のデータを取得する場合は、select句に追加する必要があります。

 records = User.joins(:posts).select('distinct users.*, posts.title as posts_title').to_a records.each do |user| puts user.name puts user.posts_title end
      
      





joinsメソッドが実行された後、user.postsを呼び出すと別のリクエストが発生することに注意してください。



オリジナル記事



All Articles