使用ActiveRecord搜索对象的关联并返回所有关联包含/不包含特定值的实例

时间:2016-09-12 21:44:41

标签: ruby-on-rails-4 activerecord associations

我尝试查询对象的关联,并且仅返回其所有关联都具有特定值的对象。例如,如果用户具有成员资格关联,并且成员资格具有有效(布尔)字段,我想返回所有的集合仅具有有效身份的成员资格的用户:false

我现在正在使用的查询是:

User.includes(:memberships).where(memberships: {active: false})

但是,这会让我拥有非活动成员资格的所有用户,以及同时拥有有效:错误有效:真实成员身份的所有用户。我尝试在这上面做一个额外的.where.not,但当然,它返回了同一组。

我考虑过映射用户集合并创建一个新数组,踢出具有活动成员资格的用户,但我需要将最终值保留为AR集合,因为我继续在控制器。

我更倾向于坚持使用ActiveRecord,但如果它不可行而我需要使用SQL,我也会对此持开放态度。

非常感谢任何帮助。谢谢!

2 个答案:

答案 0 :(得分:0)

要排除同时具有有效和无效成员资格的用户,请尝试

User.includes(:memberships).where(memberships: {active: false}).where.not(memberships: {active: true})

此外 - 您可能希望使用#joins而不是#includes。如果您不需要访问除查询之外的成员资格,则无需将其加载到内存中(#include会这样做。)

这篇文章有一个很好的解释 - http://tomdallimore.com/blog/includes-vs-joins-in-rails-when-and-where/

答案 1 :(得分:0)

在这里结合一些事情 - 你想要一个LEFT OUTTER连接,所以确保正确构建你的SQL查询。检查

User.includes(:memberships).where(memberships: {active: false}).explain

User.includes(:memberships).where(memberships: {active: false}).to_sql

其次,试试:

User.joins(:memberships).where("memberships.active = ?", false)

或者尝试.merge尝试,我喜欢使用:

User.joins(:memberships).merge(Membership.inactive)

假设您在.inactive模型

上有范围/类方法Membership
def self.inactive
  where(active: false)
end
只有当您需要将关系加载到内存中时才应该使用

.includes

编辑:

排除拥有单个(多个)成员资格的任何用户的最简单方法是将其拆分为2个查询。

active_user_ids = Membership.active.pluck(:user_id).uniq
User.where("id NOT IN (?)", active_user_ids.join(","))