模特:
scope :verified, -> { where(verified: true)}
scope :active, -> { where(active: true) }
现在,Model.active.verified
的结果为active and verified
。如何将范围链接为OR
?请注意,我不想将两个范围合并为:
where("active = ? OR verified = ?", true, true)
答案 0 :(得分:1)
您无需升级到Rails 5即可使用or
。在Rails 4中有很多方法可以做到这一点。虽然这些方法不适合在链式范围内使用,但在构建标准时可以达到类似的便利性。
Arel表。 Arel是ActiveRecord关系代数的底层实现。它支持or
以及其他强大的功能。
arel_table = Model.arel_table
Model.where(
arel_table[:active].eq(true).
or(
arel_table[:verified].eq(true)
)
)
# => SELECT "models".* FROM "models" WHERE ("models"."active" = 't' OR "models"."verified" = 't')
正如您所看到的,由于必须在or
内部应用where
,因此链接标准很复杂。在传递给where
之前,可以在外部构建标准,但同样,它们的层次结构使其不那么简单。
Monkeypatching ActiveRecord,添加or
实现。将其放入 config / initializers / active_record.rb :
ActiveRecord::QueryMethods::WhereChain.class_eval do
def or(*scopes)
scopes_where_values = []
scopes_bind_values = []
scopes.each do |scope|
case scope
when ActiveRecord::Relation
scopes_where_values += scope.where_values
scopes_bind_values += scope.bind_values
when Hash
temp_scope = @scope.model.where(scope)
scopes_where_values += temp_scope.where_values
scopes_bind_values += temp_scope.bind_values
end
end
scopes_where_values = scopes_where_values.inject(:or)
@scope.where_values += [scopes_where_values]
@scope.bind_values += scopes_bind_values
@scope
end
end
通过这种方式,您可以执行or
这样的查询:
Model.where.or(verified: true, active: true)
# => SELECT "models".* FROM "models" WHERE ("models"."verified" = $1 OR "models"."active" = $2) [["verified", "t"], ["active", "t"]]
您可以添加更多条件:
Model.where.or(verified: true, active: true, other: false)
查询可以放在这样的类方法中:
def self.filtered(criteria)
where.or(criteria) # This is chainable!
end
或在范围内,基本相同:
scope :filtered, lambda { |criteria| where.or(criteria) }
由于criteria
只是一个哈希,你可以使用任意数量的元素以方便的方式构建它:
criteria = {}
criteria[:verified] = true if include_verified?
criteria[:active] = true if include_active?
...
Model.filtered(criteria).where(... more criteria ...)
你有它。阅读更多详细信息这些SO问题:
ActiveRecord Arel OR condition
OR operator in WHERE clause with Arel in Rails 4.2
最后,如果您不反对第三方解决方案,请查看Squeel gem。