Rails - 如何将不兼容的语句与 OR 组合 (Rails 5)

Rails - how to combine incompatible statements with OR (Rails 5)

有项目模型和付款模型:

class Project < ApplicationRecord
  has_many :payments
end

class Payment < ApplicationRecord
  belongs_to :project
end

我很容易将列查询与 orand.

组合起来
Project.where(projects[:created_at].gt(6.months.ago).or(projects[:updated_at].gt(1.month.ago)))

使用 Arel 的原因是确切的列、运算符和值来自用户,而 Arel 运算符与用户可以匹配的非常好select。

但是,如果我想将它与来自另一个关联 table 的数据结合起来,那么我就不知道该怎么做。 ActiverRecord 要求 OR 在结构上兼容,所以我不能这样做:

Project.where(projects[:created_at].gt(6.months.ago)).or(Project.joins(:payments))

像这样: Project.where(projects[:created_at].gt(6.months.ago).or(projects.join(payments).on(projects[:id].eq(payments[:project_id]))))

引发异常:ActiveRecord::StatementInvalid:PG::SyntaxError:错误:子查询必须 return 只有一列。

我能够做到的一种方式是这样的: Project.where(projects[:created_at].gt(6.months.ago)).or(Project.where(id: Project.joins(:payments).select(:id)))

生成了 SQL SELECT "projects".* FROM "projects" WHERE (("projects"."created_at" > '2019-08-19 09:11:22.064298') OR "projects"."id" IN (SELECT "projects"."id" FROM "projects" INNER JOIN "payments" ON "payments"."project_id" = "projects"."id"))

这是最好的方法还是有更好的方法?请可能有 10 多个这样的子句组合在一起,涉及多个 tables,在所有可能的 tables 上使用 include 以使所有单个子句兼容可能太昂贵了。

是否有任何原因导致您无法在不同条件下保持连接一致?例如在 Rails 5+ 你可以这样写:

Project.where(some_field: '12').joins(:payments)
       .or(
           Project.where(payments: {id: '1'}).joins(:payments)
       )

这会生成 SQL 比如:

SELECT projects.* FROM projects
INNER JOIN payments ON (payments.project_id = project.id)
WHERE projects.some_field = 12 OR payments.id = 1

注:

使用 OP 中结构不兼容的示例,您可以简单地向第一个条件添加连接以使其兼容:

Project.where(projects[:created_at].gt(6.months.ago)).joins(:payments).or(Project.joins(:payments))