6

私は次のモデルを持っています:

class Rating < ActiveRecord::Base
  belongs_to :item
  belongs_to :user
end

class Item < ActiveRecord::Base
  has_many :ratings
end

すべてのアイテムと、特定のユーザーによる評価を取得して、現在のユーザーの評価 (存在する場合) を各アイテムの横に表示したいと考えています。

私はもう試した...

Item.includes(:ratings).where('ratings.user_id = ?', user_id)

...しかし、それでは評価のないアイテムは表示されません。

私が最初に考えたのは、引数との has_many 関連付けであり、その引数を includes メソッドで渡します。しかし、それは存在しないようです。

N+1 クエリを実行したり、すべてのエンティティをメモリにロードしたりせずに、パラメーターでフィルタリングされたすべての投稿と熱心に読み込まれた関連付けを取得するにはどうすればよいですか?

4

3 に答える 3

4

ステップ1

モデルレイヤーcurrent_userでアクセスできるようにします (1 つの手法がここで概説されています: https://stackoverflow.com/a/2513456/163203 )

ステップ2

実行時に評価される条件との関連付けを追加します。

レール 2

class Item < ActiveRecord::Base
  has_many :ratings
  has_many :current_user_ratings, 
           :class_name => "Rating", 
           :conditions => 'ratings.user_id = #{User.current_user.try(:id)}'
end

Rails 3.1 以降

class Item < ActiveRecord::Base
  has_many :ratings
  has_many :current_user_ratings, 
           :class_name => "Rating", 
           :conditions => proc { ["ratings.user_id = ?", User.current_user.try(:id)] }
end

ステップ 3

Item.includes(:current_user_ratings)
于 2013-04-23T18:50:11.403 に答える
0

基本的にhas_many :through関係をモデル化しているようです: Item has_and_belongs_to_many User, and Rating is the join model. :through関係についてはRails Guide to Active Record Associationsで読むことができます。

その場合は、次のようにモデルの関係を構築することをお勧めhas_many :throughします。

class Rating < ActiveRecord::Base
  attr_accessible :item_id, :user_id
  belongs_to :item
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :ratings
  has_many :rated_items, :through => :ratings
end

class Item < ActiveRecord::Base
  has_many :ratings
  has_many :rated_by_users, :through => :ratings, :source => :user
end

次に、DB に次のレコードがあるとします。

$ sqlite3 db/development.sqlite3 'SELECT * FROM items';
1|2013-03-22 03:21:31.264545|2013-03-22 03:21:31.264545
2|2013-03-22 03:24:01.703418|2013-03-22 03:24:01.703418

$ sqlite3 db/development.sqlite3 'SELECT * FROM users';
1|2013-03-22 03:21:28.029502|2013-03-22 03:21:28.029502

$ sqlite3 db/development.sqlite3 'SELECT * FROM ratings';
1|1|1|2013-03-22 03:22:01.730235|2013-03-22 03:22:01.730235

次のステートメントを使用して、関連する評価およびユーザー インスタンスとともに、すべてのアイテムを要求できます。

items = Item.includes(:rated_by_users)

これにより、3 つの SQL クエリが実行されます。

Item Load (0.1ms)  SELECT "items".* FROM "items" 
Rating Load (0.2ms)  SELECT "ratings".* FROM "ratings" WHERE "ratings"."item_id" IN (1, 2)
User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (1)

#rated_by_usersまた、各アイテムの関連付けメソッドを呼び出すことで、各アイテムを評価したユーザーにアクセスしようとすることができます。

> items.map {|item| item.rated_by_users }
=> [[#<User id: 1, created_at: "2013-03-22 03:21:28", updated_at: "2013-03-22 03:21:28">], []] 
于 2013-03-21T09:06:54.847 に答える