我想找到的所有Annotations
的尸体要么是:
什么是做到这一点的最好方法是什么?
我想用SearchLogic如果可能的话,但尽管SearchLogic允许你做以下每一项:
-
Annotation.body_equals('?')
-
Annotation.body_like('[?]')
你可以随时把它们连在一起: Annotation.body_equals('?').body_like('[?]')
我不知道如何将它们有机结合起来OR
。
请注意,您可以结合命名范围OR
如果他们的说法是一样的。 例如,我可以这样做:
Annotation.body_equals_or_body_like('?')
但是,这不会帮助。
请注意,我没有连接到SearchLogic,但它会为不需要打破它的抽象的解决方案是巨大的。
Answer 1:
我无法找到任何简单的解决方案,但这个问题吸引了我,让我滚我自己的解决方案:
class ActiveRecord::Base
def self.or_scopes(*scopes)
# Cleanup input
scopes.map! do |scope|
scope = scope.respond_to?(:to_a) ? scope.to_a : [*scope]
scope.unshift(scope.shift.to_sym)
end
# Check for existence of scopes
scopes.each{|scope| raise ArgumentError, "invalid scope: #{scope.first}" unless self.scopes.has_key?(scope.first) }
conditions = scopes.map do |scope|
scope = self.scopes[scope.first].call(self, *scope[1..-1])
self.merge_conditions(scope.proxy_options[:conditions])
end
or_conditions = conditions.compact.join(" OR ")
merged_scopes = scopes.inject(self){|merged, scope| merged.scopes[scope.first].call(self, *scope[1..-1]) }
# We ignore other scope types but so does named_scopes
find_options = merged_scopes.scope(:find).merge(:conditions => or_conditions)
self.scoped(find_options)
end
end
考虑以下设置:
class Person < ActiveRecord::Base
named_scope :men, :conditions => { :sex => 'M' }
named_scope :women, :conditions => { :sex => 'F' }
named_scope :children, :conditions => "age < 18"
named_scope :named, lambda{|name|
{ :conditions => { :name => name } }
}
end
你有一个系列示波器这样的名字称呼它:
Person.or_scopes(:women, :children)
这将返回这样一个范围:
Person.or_scopes(:women, :children).proxy_options
# => {:conditions=>"(`people`.`sex` = 'F') OR (age < 18)"}
你也可以用数组的数组时,范围需要参数调用它:
Person.or_scopes(:women, [:named, 'Sue']).proxy_options
# => {:conditions=>"(`people`.`sex` = 'F') OR (`people`.`name` = 'Sue')"}
在你的情况贺拉斯,你可以使用以下命令:
Annotation.or_scopes([:body_equals, '?'], [:body_like, '[?']).all
Answer 2:
会不“喜欢”的结果还包括了“平等”的结果吗?
您也可以使用的另一端部的命名范围,使一个很长的命名范围。 从Searchlogic文件(这样似乎有点冗长给我):
User.username_or_first_name_like("ben")
=> "username LIKE '%ben%' OR first_name like'%ben%'"
User.id_or_age_lt_or_username_or_first_name_begins_with(10)
=> "id < 10 OR age < 10 OR username LIKE 'ben%' OR first_name like'ben%'"
或者你可以使用一个联盟,同时删除重复项的搜索结果阵列组合:
@equal_results = Annotation.body_equals('?')
@like_results = Annotation.body_like('[?]')
@results = @equal_results | @like_results
Answer 3:
为Rails 2.x中,你可以使用下面的命名范围模拟OR:
__or_fn = lambda do |*scopes|
where = []
joins = []
includes = []
# for some reason, flatten is actually executing the scope
scopes = scopes[0] if scopes.size == 1
scopes.each do |s|
s = s.proxy_options
begin
where << merge_conditions(s[:conditions])
rescue NoMethodError
where << scopes[0].first.class.merge_conditions(s[:conditions])
end
joins << s[:joins] unless s[:joins].nil?
includes << s[:include] unless s[:include].nil?
end
scoped = self
scoped = scoped.includes(includes.uniq.flatten) unless includes.blank?
scoped = scoped.joins(joins.uniq.flatten) unless joins.blank?
scoped.where(where.join(" OR "))
end
named_scope :or, __or_fn
让我们使用这个功能使用你上面的例子。
q1 = Annotation.body_equals('?')
q2 = Annotation.body_like('[?]')
Annotation.or(q1,q2)
上面的代码仅执行一个查询。 q1
和q2
不持有该查询的结果,相反,他们班是ActiveRecord::NamedScope::Scope
。
该or
named_scope组合这些查询,并加入与一个OR条件。
你也可以巢OR值,就像这个人为的例子:
rabbits = Animal.rabbits
#<Animal id: 1 ...>
puppies = Animal.puppies
#<Animal id: 2 ...>
snakes = Animal.snakes
#<Animal id: 3 ...>
lizards = Animal.lizards
#<Animal id: 4 ...>
Animal.or(rabbits, puppies)
[#<Animal id: 1 ...>, #<Animal id: 2 ...>]
Animal.or(rabbits, puppies, snakes)
[#<Animal id: 1 ...>, #<Animal id: 2 ...>, #<Animal id: 3 ...>]
由于or
返回一个ActiveRecord::NamedScope::Scope
本身,我们可以去真的疯了:
# now let's get crazy
or1 = Animal.or(rabbits, puppies)
or2 = Animal.or(snakes, lizards)
Animal.or(or1, or2)
[#<Animal id: 1 ...>, #<Animal id: 2 ...>, #<Animal id: 3 ...>, #<Animal id: 4...>]
我相信,大多数的这些例子就很好地工作使用scope
中的Rails 3秒,虽然我还没有尝试过。
无耻的自我推销了一下-这个功能是可用的fake_arel宝石 。
Answer 4:
我来到这个问题寻找答案“或”两个named_scopes和所有的答案看起来太复杂了我。 我调查了一下,发现使用称为附加named_scope“或”这是卓有成效的解决方案。
下面给出的示例:
Annotation.body_equals('?')
Annotation.body_like('[?]')
都返回一个named_scope对象构造选择返回注释记录
现在我们定义了另一个名为范围预计两个命名的范围作为参数,如:
named_scope :or, lambda { |l, r| {
:conditions =>
"annotations.id IN (#{l.send(:construct_finder_sql,{:select => :id})}) or " +
"annotations.id IN (#{r.send(:construct_finder_sql,{:select => :id})})"
}}
然后,您可以使用:
Annotation.or(Annotation.body_equals('?'), Annotation.body_like('[?]'))
这将创建像查询:
select * from annotations
where (annotations.id IN (select id from annotations where body='?') or
(annotations.id IN (select id from annotations where body like '%?%')
这是你以后什么
As或也是named_scope,也能够与其他named_scopes包括另一个或链:
Annotation.or(Annotation.or(Annotation.body_equals('?'),
Annotation.body_like('[?]')),
Annotation.some_other)
Answer 5:
也许这是
Annotation.body_equals_or_body_like(['?', '[?]'])
文章来源: Combine two named scopes with OR (instead of AND)