Mic*_*ley 16 activerecord has-many-through ruby-on-rails-3
问候,
我有一个应用程序,其中Companies和Users需要通过一个CompanyMembership模型相互拥有,该模型包含有关成员资格的额外信息(具体来说,用户是否是公司的管理员,通过布尔值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
Run Code Online (Sandbox Code Playgroud)
当然,这使得通过公司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
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但它的效率却很低(它会迭代每个成员资格,每次都执行SQL,对吗?或者是比这更聪明的关系吗?),我不确定是否有更好的方法来解决这个问题(可能使用范围或RelationRails 3使用的花哨的新对象?).
任何关于最佳处理方式的建议(最好使用Rails 3最佳实践)将不胜感激!
Mic*_*ley 17
我相信我的方法是错误的,指定条件company_memberships而不是users,这是我真正想要的(列表Users,而不是列表CompanyMemberships).我认为我正在寻找的解决方案是:
users.where(:company_memberships => {:admin => true})
Run Code Online (Sandbox Code Playgroud)
生成以下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')
Run Code Online (Sandbox Code Playgroud)
我不确定我是否需要它,但该includes()方法将执行急切加载以在必要时保持SQL查询的数量:
Active Record允许您事先指定要加载的所有关联.这可以通过指定调用
includes方法来实现Model.find.使用includes,Active Record可确保使用尽可能少的queries.queries加载所有指定的关联.RoR指南:ActiveRecord查询
(对于那些认为这不是最好/最有效/最正确的方法的人,我仍然愿意接受任何建议.)
更简洁的方法是在公司模型中添加关联,如下所示:
has_many :admins, :through => :company_memberships, :class_name => :user, :conditions => {:admin => true}
Run Code Online (Sandbox Code Playgroud)
您可能需要深入研究rails doc以获得正确的语法.
您不应该:include,除非您有其他类与您关联:您可能在视图中引用的用户.
| 归档时间: |
|
| 查看次数: |
24543 次 |
| 最近记录: |