Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何将范围查询链接到AND或替代AND?_Ruby On Rails_Ruby On Rails 3_Activerecord_Rails Activerecord - Fatal编程技术网

Ruby on rails 如何将范围查询链接到AND或替代AND?

Ruby on rails 如何将范围查询链接到AND或替代AND?,ruby-on-rails,ruby-on-rails-3,activerecord,rails-activerecord,Ruby On Rails,Ruby On Rails 3,Activerecord,Rails Activerecord,我用的是Rails3,ActiveRecord 我只是想知道如何用OR语句而不是AND语句来链接作用域 e、 g 通常返回: name = 'John' AND lastname = 'Smith' 但我想: `name = 'John' OR lastname = 'Smith' 你会的 Person.where('name=? OR lastname=?', 'John', 'Smith') 目前,新的AR3语法(即不使用某些第三方gem)没有任何其他功能或支持 您还可以使用gem来避

我用的是Rails3,ActiveRecord

我只是想知道如何用OR语句而不是AND语句来链接作用域

e、 g

通常返回:

name = 'John' AND lastname = 'Smith'
但我想:

`name = 'John' OR lastname = 'Smith'
你会的

Person.where('name=? OR lastname=?', 'John', 'Smith')
目前,新的AR3语法(即不使用某些第三方gem)没有任何其他功能或支持

您还可以使用gem来避免代码与SQL内容混淆:

Person.where((:name => "John") | (:lastname => "Smith"))

如果您使用的是Rails3.0+,那么这将是MetaWhere的一个很好的候选者,但它在Rails3.1上不起作用。你可能想试试看。它是由同一作者制作的。以下是您如何执行基于OR的链:

Person.where{(name == "John") | (lastname == "Smith")}

您可以混合和匹配和/或,等等。

如果有人正在寻找此问题的更新答案,那么看起来有一个现有的拉入请求将其放入Rails:

感谢@j-mcnally的用于ActiveRecord()的猴子补丁,您可以执行以下操作:

Person.where(name: 'John').or.where(last_name: 'Smith').all
更重要的是能够将作用域链接到

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

这不是最好的例子,但只是想把它与问题结合起来。

squel
gem提供了一种非常简单的方法来实现这一点(在此之前,我使用了类似@coloradoblue的方法):


如果您无法手动写出where子句以包含“or”语句(即,您希望合并两个作用域),则可以使用union:

Model.find_by_sql("#{Model.scope1.to_sql} UNION #{Model.scope2.to_sql}")
(来源:)

这将返回与任一查询匹配的所有记录。但是,这将返回一个数组,而不是arel。如果您真的想退回arel,请签出以下要点:

只要你不介意用猴子修补铁轨,这就行了

轨道4

scope :combined_scope, -> { where("name = ? or name = ?", 'a', 'b') }
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

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)
)
旧答案

不需要第三方宝石

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

Rails/ActiveRecord的更新版本可能本机支持此语法。它看起来类似于:

Foo.where(foo: 'bar').or.where(bar: 'bar')
如本请求中所述

目前,只要坚持以下几点就可以了:

Foo.where('foo= ? OR bar= ?', 'bar', 'bar')

只需发布相同的列或查询的数组语法即可帮助窥视

Person.where(name: ["John", "Steve"])
对于我(Rails 4.2.5),它的工作原理如下:

{ where("name = ? or name = ?", a, b) }
另请参见以下相关问题:,以及

对于rails 4,基于和

注意文章结尾的注意事项:

轨道4.1+

Rails 4.1将默认范围视为常规范围。默认值 范围(如果有)包含在where_值结果和 inject(:or)将在默认范围和 在哪里。那太糟糕了

要解决这个问题,只需取消查询的作用域

根据,Rails 5现在支持以下链接查询语法:

Post.where(id: 1).or(Post.where(id: 2))

另外,Rails 4.2还通过

提供了一个功能的后端口,因此原始问题的答案是,你能用“或”而不是“和”来连接作用域吗。但是,您可以手工编写一个完全不同的作用域或查询来完成这项工作,或者使用与ActiveRecord不同的框架,例如MetaWhere或Squel。对我来说没用

我正在“或”使用pg_搜索生成的范围,它的功能比select稍多,它包括order by ASC,这会把一个干净的联合弄得一团糟。我想“或”它与手工制作的范围,做的东西,我不能在pg_搜索。所以我不得不这样做

Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")
也就是说,将作用域转换为sql,在每个作用域周围放上括号,将它们合并在一起,然后使用生成的sql逐个查找sql。这有点垃圾,但确实有用


不,不要告诉我我可以在pg_搜索中使用“反对:[:名称,:代码]”,我想这样做,但“名称”字段是一个hstore,pg_搜索还不能处理它。因此,按名称划分的范围必须手工编制,然后与pg_搜索范围合并

如果您希望提供一个作用域(而不是显式地处理整个数据集),那么您应该使用Rails 5:

scope :john_or_smith, -> { where(name: "John").or(where(lastname: "Smith")) }
或:


这是一种非常方便的方法,在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")
  )

有人能评论一下这种类型的查询在Postgres中是否会中断吗?ARel应该是DB不可知的。虽然这看起来是个好主意,但ARel不是一个公共API,使用它可能会以意外的方式中断你的应用程序,所以我建议你不要这样做,除非你密切关注ARel API的发展。@OlivierLacan ARel是一个公共API,或者更准确地说,它暴露了一个问题。Active Record只提供了在幕后使用它的方便方法,单独使用它是完全有效的。它遵循语义版本控制,因此除非您更改主要版本(3.x.x=>4.x.x),否则不必担心破坏更改。为了安全起见,将其表示为Person是值得的。其中(“name=?或lastname=?”,“John”,“Smith”)仍然适用于Rails 4?Rails 4中没有更好的东西了?Rails 4没有变化,但是Rails 5。这不是作用域,只是2个where子句,或者是一个非常特定的作用域情况。如果我想链接更复杂的作用域,比如使用连接,那么该怎么办呢?使用Rails 5,您还可以执行诸如Person.where(“name='John'))或(Person.where(“lastname='Smith'))+1之类的操作。MetaWhere的继承者是同一位作者。从资源和方法的角度来看,这确实是OP问题的唯一纯粹答案。其他答案要么(a)需要第三方API,要么(b)需要在文本块中插入
或其他运算符,这两者都没有反映在OP的代码中。这里有一篇不错的文章解释它使用
…where_values.join('or')
,在我的例子中,您可以省略
。点击{sc | sc.bind_values=[a,b]。map(&:bind_values)}
part如果你的作用域没有任何需要绑定的变量。你需要哪个版本或Rails?最新的讨论和拉入请求将使其成为Rails核心
Post.where(id: 1).or(Post.where(id: 2))
Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")
scope :john_or_smith, -> { where(name: "John").or(where(lastname: "Smith")) }
def self.john_or_smith
  where(name: "John").or(where(lastname: "Smith"))
end
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")
  )