我的应用中有很多案例,用户在与另一个对象(“组”)的关联中只有一个对象(比如“描述”)。
例如:
class User < ActiveRecord::Base
has_many :descriptions
has_many :groups
class Group < ActiveRecord::Base
has_many :users
has_many :descriptions
class Description < ActiveRecord::Base
belongs_to :user
belongs_to :group
如果我想渲染特定群组中的所有用户并包含相关说明,我可以做一些事情:
#users model
def description_for(group_id)
descriptions.find_by_group_id(group_id)
end
#view
@group.users.each do |user|
user.name
user.description_for(@group.id).content
但是这会产生大量的描述查询。我尝试过使用连接:
#controller
@group = Group.find(params[:id], :joins => [{:users => :descriptions}], :conditions => ["descriptions.group_id = ?", params[:id]])
但是因为我仍在调用user.description_for(@ group.id),所以它对页面加载没有帮助。
更新:示例生成的SQL
Rendered users/_title.html.haml (1.6ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 7 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.1ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 7 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 7 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.7ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 51 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.1ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 51 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 51 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.8ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.1ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 5 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 5 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.7ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 52 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.2ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 52 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 52 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.7ms)
答案 0 :(得分:1)
是的,我认为实际上你不需要rails 3中的joins子句。如果你使用include和where,Arel会为你做艰苦的工作。
我已经测试了这个(尽管使用了一组不同于你的模型(和属性))使用具有相同基本排列关联的模型,我认为这应该有效:
在models / user.rb中:
scope :with_group_and descriptions, lambda { |group_id| includes(:groups, :descriptions).where(:groups => { :id => group_id }, :descriptions => { :group_id => group_id }) }
然后在你的控制器中你打电话:
@users = User.with_group_and_descriptions(params[:id])
最后在视图中,您可以这样做:
@users.each do |user|
user.name
user.descriptions.each do |desc|
desc.content
# or
@users.each do |user|
user.name
user.descriptions[0].content
如果我的想法正确,那么这应该只进行2个db调用。一个用于获取user_ids列表,另一个用于获取用户,组和描述数据,即使您正在调用用户对象的描述方法,该方法通常包含所有描述(不仅仅是特定组的描述) ),因为你已经填充了关联栏,当你拨打user.descriptions
时,栏杆不会再次抓取所有关联,而是只使用描述列出你从数据库中提取的那些。 group_id where子句。但是,调用user.descriptions(true)
将强制重新加载描述,从而返回一个所有用户的描述关联数组。
答案 1 :(得分:-1)
看一下include
- 它指定了一个应该加载的关联。