Создание фильтров с комбинацией И и ИЛИ рельсов - PullRequest
0 голосов
/ 18 декабря 2018

Я нахожусь в ситуации, чтобы отфильтровать записи на основе некоторых условий (условия в форме областей).в пользовательской модели

scope :has_email, -> { where('email IS NOT NULL') }
scope :email_contains, (email) -> { where("email ILIKE :email'", email: email)}

Если я хочу, чтобы оба условия были объединены с оператором 'И', мы можем сделать что-то вроде

User.has_email.email_contains

Сгенерированный запрос будет

SELECT "user".* FROM "user" WHERE (email ILIKE '%gmail.com%') AND (email IS NOT NULL)

Как мне действовать, если мне нужно объединить области с операторами OR?Я обнаружил, что в rails 5 добавлена ​​поддержка метода or (https://blog.bigbinary.com/2016/05/30/rails-5-adds-or-support-in-active-record.html), Но это не сработает, если мы используем include или join

Например: User.has_email.or(User.some_scope).or(User.joins(:event).temp)

Как сделатьЯ присоединяюсь к областям с OR?

1 Ответ

0 голосов
/ 18 декабря 2018

Вам не хватает того, что соединение заставляет ассоциацию существовать.Чтобы предотвратить это, вы используете left_joins:

User.left_joins(:event).where(event: {foo: bar})

Тем не менее это не решит проблему, потому что метод .or будет работать (по документации) только для структурно эквивалентных отношений.

Вы можете фактически преодолеть это, перейдя на шаг ниже к Arel:

rels = [User.foo, User.bar(baz), User.joins(:event).temp]
cond = rels.map { |rel| rel.where_values.reduce(&:and) }.reduce(&:or)
User.left_joins(:event).where(cond)

Свойство where_values является массивом экземпляров Arel :: Nodes :: Node, каждый из которых обычно andчтобы получить ваш запрос.Вы должны and их вручную, а затем or результаты.

Если что-то не работает должным образом, проверьте вывод cond.to_sql на случай, если вы что-то пропустили.

...