这个特定主题有很多答案,但我找不到任何适合我的答案。我有一个配方应用程序,我需要所有给该配方特定评级的用户(例如:给特定配方评级为5的用户列表),而没有n + 1查询错误。我知道它可以使用包含选项解决,但属于参考我不知道如何使用它。我正在使用rails 3.2.15。
下面是我的应用程序的模态级别描述
class Recipe < ActiveRecord::Base
belongs_to :user, :foreign_key => 'creator_id'
has_many :photos, :dependent => :destroy
has_many :recipe_ingredients
has_many :ingredients, :through => :recipe_ingredients
has_many :ratings, :dependent => :destroy
end
class Rating < ActiveRecord::Base
belongs_to :user, :foreign_key => 'rater_id'
belongs_to :recipe
end
class Ingredient < ActiveRecord::Base
belongs_to :user, :foreign_key => 'creator_id'
has_many :recipe_ingredients
has_many :recipes, :through => :recipe_ingredients
end
class User < ActiveRecord::Base
has_many :recipes , foreign_key: "creator_id", class_name: "Recipe", :dependent => :destroy
has_many :ingredients, foreign_key: "creator_id", class_name: "Ingredient", :dependent => :destroy
has_many :ratings, foreign_key: "rater_id", class_name: "Rating", :dependent => :destroy
end
我检索用户的查询是
@rec = Recipe.find(params[:id])
ratings = @rec.ratings.where(:ratings => params[:ratings])
users = ratings.map {|rate| rate.user}
这引入了一个n + 1查询错误,有没有正确使用rails的方法?
答案 0 :(得分:1)
修改后的查询:
users = ratings.includes(:user).select('users.name')
考虑到您在用户中有名称列,我添加了select('users.name')
。您可以使用所需的任何列进行视图。
答案 1 :(得分:1)
@VedprakashSingh 的回答有一个主要的缺点,即返回Rating
填充了来自User
的数据的实例。所以,突然之间,你没有采用User
的所有方法。类型安全被扔出窗外。
您可以做的是使用joins
/ merge
组合来获取另一个模型的实例。像这样:
User.joins(:ratings).merge(
# Here you can place a relation of ratings
@rec.ratings.where(:ratings => params[:ratings])
# Yes, it's your line, copy-pasted from your question
) # ...and back here we get users joined with these
因此,您明确地使用您想要User
的事实启动查询。然后你加入表格,得到一个巨大的集合,每个评级与user
一起加入(所有评级都在数据库中!)。 merge
的内容会将该集中的评分过滤为您想要的评分。
小心,因为我从问题中复制的行可能容易受到伪造参数的影响,因此未对其进行过滤。您有ratings
表格,因此,如果params[:ratings]
变成哈希(可以完成,它实际上就是用户的输入),它将会被视为条件的哈希,允许用户发送任何基于哈希的条件。
yoursite.com/whatever?ratings[id]=12
该查询字符串将导致params[:ratings]
:
{"id" => "12"} # Damn right, a Ruby hash
Strong parameters存在是有原因的。