Answers:
你会做
Person.where('name=? OR lastname=?', 'John', 'Smith')
目前,新的AR3语法不提供任何其他OR支持(即不使用某些第三方宝石)。
使用ARel
t = Person.arel_table
results = Person.where(
t[:name].eq("John").
or(t[:lastname].eq("Smith"))
)
只需发布同一列或查询的Array语法即可帮助窥视。
Person.where(name: ["John", "Steve"])
Rails4的更新
不需要第三方宝石
a = Person.where(name: "John") # or any scope
b = Person.where(lastname: "Smith") # or any scope
Person.where([a, b].map{|s| s.arel.constraints.reduce(:and) }.reduce(:or))\
.tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }
旧答案
不需要第三方宝石
Person.where(
Person.where(:name => "John").where(:lastname => "Smith")
.where_values.reduce(:or)
)
or
在文本块内进行插值或其他运算符,而这两个都不反映在OP的代码中。
...where_values.join(' OR ')
在我的情况
.tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }
如果您的范围没有任何需要绑定的变量,则可以省略该部分。
您还可以使用MetaWhere gem将代码与SQL内容不混淆:
Person.where((:name => "John") | (:lastname => "Smith"))
如果有人在寻找对此的更新答案,则似乎已经存在将其放入Rails的拉取请求:https : //github.com/rails/rails/pull/9052。
感谢@ j-mcnally的ActiveRecord猴子补丁(https://gist.github.com/j-mcnally/250eaaceef234dd8971b),您可以执行以下操作:
Person.where(name: 'John').or.where(last_name: 'Smith').all
更加有价值的是具有以下能力的范围链接能力OR
:
scope :first_or_last_name, ->(name) { where(name: name.split(' ').first).or.where(last_name: name.split(' ').last) }
scope :parent_last_name, ->(name) { includes(:parents).where(last_name: name) }
然后,您可以找到所有具有名字或姓氏的人,或者其父母是姓氏的人
Person.first_or_last_name('John Smith').or.parent_last_name('Smith')
这不是使用此方法的最佳示例,而只是尝试使其适合问题。
.or
链功能。我能够使用在Rails> = 3.2上提到的猴子补丁;但是,您可能需要等待Rails 5对代码进行任何长期的更改。
Rails / ActiveRecord的更新版本可能会原生支持此语法。它看起来类似于:
Foo.where(foo: 'bar').or.where(bar: 'bar')
如该拉取请求所述https://github.com/rails/rails/pull/9052
现在,只需坚持以下工作即可:
Foo.where('foo= ? OR bar= ?', 'bar', 'bar')
Foo.where(foo: 'bar1').or.where(bar: 'bar2')
不起作用。应该是Foo.where(foo:'bar1')。或.where(Foo.where(bar:'bar2'))
Rails 4 +范围+ Arel
class Creature < ActiveRecord::Base
scope :is_good_pet, -> {
where(
arel_table[:is_cat].eq(true)
.or(arel_table[:is_dog].eq(true))
.or(arel_table[:eats_children].eq(false))
)
}
end
我尝试用.or链接命名的作用域,但是没有运气,但是这对于用这些布尔值集查找任何东西都是有用的。像生成SQL
SELECT 'CREATURES'.* FROM 'CREATURES' WHERE ((('CREATURES'.'is_cat' = 1 OR 'CREATURES'.'is_dog' = 1) OR 'CREATURES'.'eats_children' = 0))
如果您想提供一个范围(而不是显式地处理整个数据集),那么您应该对Rails 5进行以下操作:
scope :john_or_smith, -> { where(name: "John").or(where(lastname: "Smith")) }
要么:
def self.john_or_smith
where(name: "John").or(where(lastname: "Smith"))
end
如果您无法手动写出where子句以包含“ or”语句(即,您想合并两个作用域),则可以使用union:
Model.find_by_sql("#{Model.scope1.to_sql} UNION #{Model.scope2.to_sql}")
这将返回与任一查询匹配的所有记录。但是,这将返回一个数组,而不是一个arel。如果您真的想退回竞技场,请查看以下要点:https ://gist.github.com/j-mcnally/250eaaceef234dd8971b 。
只要您不介意猴子修补滑轨,就可以完成此工作。
Person
.unscoped # See the caution note below. Maybe you want default scope here, in which case just remove this line.
.where( # Begin a where clause
where(:name => "John").where(:lastname => "Smith") # join the scopes to be OR'd
.where_values # get an array of arel where clause conditions based on the chain thus far
.inject(:or) # inject the OR operator into the arels
# ^^ Inject may not work in Rails3. But this should work instead:
.joins(" OR ")
# ^^ Remember to only use .inject or .joins, not both
) # Resurface the arels inside the overarching query
请注意文章最后的警告:
Rails 4.1+
Rails 4.1将default_scope视为常规作用域。默认范围(如果有的话)包含在where_values结果中,并且inject(:or)将在默认范围和您的位置之间添加或声明。那很糟。
为了解决这个问题,您只需要取消范围查询。
这是一种非常方便的方法,并且在Rails 5中可以正常工作:
Transaction
.where(transaction_type: ["Create", "Correspond"])
.or(
Transaction.where(
transaction_type: "Status",
field: "Status",
newvalue: ["resolved", "deleted"]
)
)
.or(
Transaction.where(transaction_type: "Set", field: "Queue")
)
因此,对于原始问题的答案是,您可以将合并范围用“或”而不是“和”似乎是“不可以吗”。但是您可以手工编写一个完全不同的作用域或查询来完成工作,或者使用与ActiveRecord不同的框架,例如MetaWhere或Squeel。对我来说没有用
我正在“或”由pg_search生成的作用域,该作用域比select还要多,它包括ASC的顺序,这使干净的联合变得一团糟。我想用一个手工制作的示波器“或”它来做我在pg_search中做不到的事情。所以我必须这样做。
Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")
即将范围转换为sql,将方括号括起来,将它们合并在一起,然后使用生成的sql查找find_by_sql。有点垃圾,但是确实有效。
不,不要告诉我我可以在pg_search中使用“反对:[:name,:code]”,我想这样做,但是'name'字段是一个hstore,pg_search无法处理然而。因此,按名称命名的范围必须手工制作,然后与pg_search范围合并。