在Rails 3中的has_many:through关系中过滤子对象

Mic*_*ley 16 activerecord has-many-through ruby-on-rails-3

问候,

我有一个应用程序,其中CompaniesUsers需要通过一个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查询

(对于那些认为这不是最好/最有效/最正确的方法的人,我仍然愿意接受任何建议.)


Ed *_*ood 8

更简洁的方法是在公司模型中添加关联,如下所示:

has_many :admins, :through => :company_memberships, :class_name => :user, :conditions => {:admin => true}
Run Code Online (Sandbox Code Playgroud)

您可能需要深入研究rails doc以获得正确的语法.

您不应该:include,除非您有其他类与您关联:您可能在视图中引用的用户.

  • @CeasarBautista 这个答案似乎已经过时了。请参阅“自定义查询”标题下的文档,其中告诉您使用 `-&gt;` (2认同)