问候,
我有一个应用程序,其中Companies
和Users
需要通过CompanyMembership
模型彼此归属,该模型包含有关成员资格的额外信息(具体而言,用户是否通过 bool(boolean) 值admin
成为公司的管理员)。代码的简单版本:
class CompanyMembership < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
class Company < ActiveRecord::Base
has_many :company_memberships
has_many :users, :through => :company_memberships
end
class User < ActiveRecord::Base
has_many :company_memberships
has_many :companies, :through => :company_memberships
end
当然,这使得通过
company.users.all
等获取公司的所有成员变得很容易。但是,我试图获取公司中所有该公司管理员的用户列表(并测试用户是否是给定公司的管理员)。我的第一个解决方案是company.rb
中的以下内容:def admins
company_memberships.where(:admin => true).collect do |membership|
membership.user
end
end
def is_admin?(user)
admins.include? user
end
虽然这样做有效,但感觉有些效率低下(它遍历每个成员资格,每次执行SQL,对吗?还是Relation比它更聪明?),我不确定是否有更好的方法(也许使用范围还是Rails 3使用的新的
Relation
对象?)。任何有关最佳操作方式的建议(最好使用Rails 3最佳实践)将不胜感激!
最佳答案
我相信我会用这种错误的方式,在company_memberships
而不是users
上指定条件,而这正是我真正想要的(Users
列表,而不是CompanyMemberships
列表)。我想寻找的解决方案是:
users.where(:company_memberships => {:admin => true})
生成以下SQL(对于ID为1的公司):
SELECT "users".* FROM "users"
INNER JOIN "company_memberships"
ON "users".id = "company_memberships".user_id
WHERE (("company_memberships".company_id = 1))
AND ("company_memberships"."admin" = 't')
我不确定是否需要它,但是必要时
includes()
方法将执行急切的加载以减少SQL查询的数量:Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the
includes
method of theModel.find
call. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.queries. RoR Guides: ActiveRecord Querying
(我仍然接受任何认为这不是解决此问题的最佳/最有效/正确方法的人的任何建议。)
关于activerecord - 在Rails 3中的has_many:through关系中过滤子对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3753625/