【问题标题】:Creating filters with combination of AND and OR rails使用 AND 和 OR 轨道组合创建过滤器
【发布时间】:2018-12-18 12:10:31
【问题描述】:

我的情况是根据某些条件过滤记录(条件是范围的形式)。在用户模型中

scope :has_email, -> { where('email IS NOT NULL') }
scope :email_contains, (email) -> { where("email ILIKE :email'", email: email)}

如果我想将这两个条件与“AND”运算符结合起来,我们可以这样做,

User.has_email.email_contains

生成的查询将是

SELECT "user".* FROM "user" WHERE (email ILIKE '%gmail.com%') AND (email IS NOT NULL)

如果我需要将作用域与OR 运算符结合使用,我该如何进行?我发现rails 5增加了对or方法(https://blog.bigbinary.com/2016/05/30/rails-5-adds-or-support-in-active-record.html)的支持,但是如果我们使用includes或者joins就不行了

例如:User.has_email.or(User.some_scope).or(User.joins(:event).temp)

如何使用OR 加入范围?

【问题讨论】:

  • 但是在上面给出的示例中,如果电子邮件为 NULL,如果我们知道电子邮件为 NULL,为什么还要检查电子邮件的值?
  • 我的用例很复杂,我只是想解释一下我需要的逻辑。
  • 嗯好的。不过,您可以在单个范围内执行 OR。不太确定在级联范围时是否有 OR 方法。

标签: ruby-on-rails activerecord ruby-on-rails-5 active-record-query


【解决方案1】:

您缺少的一点是连接强制关联存在。为了防止这种情况,你使用left_joins:

User.left_joins(:event).where(event: {foo: bar})

它仍然不能解决问题,因为 .or 方法将(通过文档)仅适用于结构等效的关系。

你实际上可以通过降低一步,到 Arel 来克服它:

rels = [User.foo, User.bar(baz), User.joins(:event).temp]
cond = rels.map { |rel| rel.where_values.reduce(&:and) }.reduce(&:or)
User.left_joins(:event).where(cond)

where_values 属性是 Arel::Nodes::Node 实例的数组,所有这些实例通常都是 and-ed 以获取您的查询。您必须手动and 他们,然后or 结果。

如果某些事情没有按预期工作,请检查cond.to_sql 的输出以防您遗漏了什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-07
    • 2015-04-26
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多