Как связать запросы области с помощью ИЛИ вместо И? - PullRequest
128 голосов
/ 10 сентября 2010

Я использую Rails3, ActiveRecord

Просто интересно, как можно связать области видимости с помощью операторов OR вместо AND.

например.

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

Это обычно возвращает:

name = 'John' AND lastname = 'Smith'

но я бы хотел:

`name = 'John' OR lastname = 'Smith'

Ответы [ 19 ]

96 голосов
/ 10 сентября 2010

Вы бы сделали

Person.where('name=? OR lastname=?', 'John', 'Smith')

. В настоящее время нет никакой другой ИЛИ поддержки нового синтаксиса AR3 (то есть без использования каких-либо сторонних гемов).

45 голосов
/ 10 сентября 2010

Использование ARel

t = Person.arel_table

results = Person.where(
  t[:name].eq("John").
  or(t[:lastname].eq("Smith"))
)
44 голосов
/ 20 марта 2017

Согласно этому запросу на извлечение , Rails 5 теперь поддерживает следующий синтаксис для формирования цепочек запросов:

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

Существует также обратный порт функциональности в Rails 4.2 через thisдрагоценный камень.

38 голосов
/ 21 ноября 2014

Обновление для 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)
)
36 голосов
/ 25 июля 2015

Просто отправьте синтаксис Array для того же столбца ИЛИ запросов, чтобы выглядело.

Person.where(name: ["John", "Steve"])
22 голосов
/ 12 августа 2013

В случае, если кто-то ищет обновленный ответ на этот вопрос, похоже, что существует существующий пул-запрос для передачи его в Rails: https://github.com/rails/rails/pull/9052.

Благодаря патчу @ j-mcnally для ActiveKecord(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')

Не лучший пример для использования этого, но просто пытаюсь соответствовать этому вопросу.

21 голосов
/ 10 сентября 2010

Вы также можете использовать MetaWhere gem, чтобы не перепутать ваш код с SQL-компонентами:

Person.where((:name => "John") | (:lastname => "Smith"))
9 голосов
/ 29 июня 2016

Для меня (Rails 4.2.5) это работает только так:

{ where("name = ? or name = ?", a, b) }
8 голосов
/ 18 декабря 2014

Обновленная версия Rails / ActiveRecord может изначально поддерживать этот синтаксис. Это будет выглядеть примерно так:

Foo.where(foo: 'bar').or.where(bar: 'bar')

Как отмечено в этом запросе на извлечение https://github.com/rails/rails/pull/9052

На данный момент, просто придерживаться следующих работ прекрасно работает:

Foo.where('foo= ? OR bar= ?', 'bar', 'bar')
8 голосов
/ 12 января 2012

Это был бы хороший кандидат для MetaWhere, если вы используете Rails 3.0+, но он не работает на Rails 3.1. Возможно, вы захотите попробовать squeel . Это сделано тем же автором. Вот как бы вы выполнили цепочку на основе ИЛИ:

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

Вы можете смешивать и сочетать И / ИЛИ, среди многих других удивительных вещей .

...