Rails 5 ActiveRecord - объединить предложения OR и AND

Я не могу понять правильный синтаксис при включении нескольких моделей и использовании предложений AND или OR. Например, есть Shop модель, которая has_one связана с Address моделью и belongs_to с Country. Как, например, добавить OR к следующему запросу:

Shop.includes(:address, :country)

Пытаюсь так:

Shop.includes(:address, :country).where('countries.code'=> 'FR').and('counties.updated_at > ?', Date.today.days_ago(7))

вызывает ошибку:

NoMethodError: undefined method `and' for #<Shop::ActiveRecord_Relation:0x00007fb90d0ea3f8>

Я нашел этот thread в SO, но в этом случае я должен повторить одно и то же предложение where перед каждым оператором OR? - выглядит не так СУХО :( Чего мне не хватает?


person belgoros    schedule 12.03.2019    source источник


Ответы (2)


Не пинайте себя... не нужно использовать и вообще, просто вставьте другое куда в:

Shop.includes(:address, :country).where('countries.code'=> 'FR').where('counties.updated_at > ?', Date.today.days_ago(7))
person Mark    schedule 12.03.2019
comment
спасибо, он генерирует предложение AND, но как насчет OR? - person belgoros; 12.03.2019
comment
Это будет работать: shops = Shop.includes(:country, :address).where('countries.code'=> 'BE').or(Shop.includes(:country, :address).where('countries.updated>?', Date.today.days_ago(10))) но слишком многословно и СУХО. - person belgoros; 12.03.2019
comment
Это выглядит настолько чистым, насколько это возможно.. может быть, разделить их на две разные переменные, чтобы они выглядели немного лучше, но я не могу придумать более быстрого способа, чем этот. - person Mark; 12.03.2019
comment
метод «ИЛИ» работает так, как вы ожидаете, и когда вам нужно «И», просто замените его другим «где» - person Mark; 12.03.2019
comment
Ок, спасибо, можно вынести в отдельную область, будет СУШЕЕ... - person belgoros; 12.03.2019

Существует лучшее решение, если вам нужно добавить несколько предложений OR в предложение AND. Чтобы обойти это, существует метод arel_table, который можно использовать следующим образом. Допустим, у нас есть следующие модели

Shop -> has_one :address
Shop -> belongs_to :country

и мы хотели бы найти все магазины по коду страны, а адрес updated_at или страна updated_at должны быть больше, чем дата, которую вы вводите:

some_date = Date.today
countries = Country.arel_table
addresses = Address.arel_table

# creating a predicate using arel tables

multi_table_predicate = countries[:updated_at].gt(some_date).or(addresses[:updated_at].gt(some_date))

# building the query

shops = Shop.includes(:address, :country).where(countries: {code: 'FR'}).where(multi_table_predicate)

Это выполнит LEFT OUTER JOIN и вот where предложение:

WHERE "countries"."code" = $1 AND ("countries"."updated_at" > '2019-03-12' OR "addresses"."updated_at" > '2019-03-12')

Конечно, вы можете связать больше таблиц и умножить OR условий, если хотите.

Надеюсь это поможет.

person belgoros    schedule 12.03.2019