Запрос ActiveRecord OR Hash

Я знаю, что есть 3 основных обозначения для предоставления аргументов where метода ActiveRecord:

  • Чистая строка
  • Массив
  • Hash

Указание and для метода where выполняется прямо:

# Pure String notation
Person.where("name = 'Neil' AND age = 27")

# Array notation
Person.where(["name = ? AND age = ?", 'Neil', 27])

# Hash notation
Person.where({name: "Neil", age: 27})

Указание or для этого же метода where - это то, что я хочу использовать для хеш-синтаксиса. Возможно ли это?

# Pure String notation
Person.where("name = 'Neil' OR age = 27")

# Array notation
Person.where(["name = ? OR age = ?", 'Neil', 27])

# Hash notation DOESN'T WORK
Person.where({name: "Neil" OR age: 27})

Ответ 1

Существует 5 вариантов, которые можно было бы рассматривать как реализации "Обозначения хэша" (последние два имеют вид хэш-иш):

  • С Ruby on Rails 5 вы можете выполнить следующую цепочку с помощью метода ActiveRecord::Relation#or:

    Person.where(name: 'Neil').or(Person.where(age: 27))
    
  • Используйте where_values вместе с reduce. unscoped необходим только для Rails 4.1+ для обеспечения default_scope не включен в where_values. В противном случае предикаты из default_scope и where будут связаны цепью с оператором or:

    Person.where( 
      Person.unscoped.where(name: ['Neil'], age: [27]).where_values.reduce(:or) 
    )
    
  • Установите сторонние плагины, реализующие эти или подобные функции, например:

    • Где или (обратная сторона упомянутой выше функции Ruby on Rails 5 .or)

    • Squeel

      Person.where{(name == 'Neil') | (age == 27)} 
      
    • RailsOr

      Person.where(name: 'Neil').or(age: 27)
      
    • ActiverecordAnyOf

      Person.where.anyof(name: 'Neil', age: 27)
      
    • SmartTuple

      Person.where(
        (SmartTuple.new(' or ') << {name: 'Neil', age: 27}).compile
      )
      
  • Используйте Arel:

    Person.where( 
      Person.arel_table[:name].eq('Neil').or(
        Person.arel_table[:age].eq(27)
      ) 
    )
    
  • Используйте подготовленные инструкции с именованными параметрами:

    Person.where('name = :name or age = :age', name: 'Neil', age: 27)
    

Ответ 2

Как говорит potashin, вы можете использовать другие сторонние плагины, которые реализуют эту функцию. Я долгое время использовал Squeel и отлично работает для этого и гораздо больше функций, таких как сложные подзапросы или объединения.

Этот запрос с использованием squeel:

@people= Person.where{(name == 'Neil') | (age = 27)}