Rails-如何将不兼容的语句与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运算符与用户可以选择的内容非常匹配。

然而,如果我想将其与另一个关联表中的数据结合起来,那么我就不知道该怎么办了。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:ERROR:子查询只能返回一列。

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

生成SQLSELECT "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多个这样的子句组合在一起,涉及多个表,在所有可能的表上使用include使所有单独的子句兼容可能过于昂贵。

有什么原因不能在不同条件下保持联接的一致性吗?例如,在Rails5+中,您可以编写:

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))

最新更新