Rails 5: ActiveRecord АБО запит


Відповіді:


228

Можливість ланцюга orпункту разом із запитом whereу ActiveRecordзапиті буде доступна в Rails 5 . Дивіться відповідні обговорення та запит на тягнення .

Отже, у Rails 5 ви зможете зробити наступні дії :

Для того, щоб отримати postз id1 або 2:

Post.where('id = 1').or(Post.where('id = 2'))

Деякі інші приклади:

(A&& B) || C:

    Post.where(a).where(b).or(Post.where(c))

(A || B) & C:

    Post.where(a).or(Post.where(b)).where(c)

3
Як я можу отримати (A || B) && (C || D). Я спробував Post.where (a) .or (Post.where (b)). Where (c) .or (Post.where (d)), але він виробляє як: (A || B) & C || Д
Імран Ахмад

3
@Imran Я вважаю, що саме Post.where(a).or(Post.where(b)).where(Post.where(c).or(Post.where(d)))це повинно створити (a || b) && (c || d)
engineersmnky

1
@Imran Це, здається, не працює для мене: я отримуюArgumentError: Unsupported argument type: #<MyModel::ActiveRecord_Relation:0x00007f8edbc075a8> (MyModel::ActiveRecord_Relation)
Suan

5
Еквівалент .or, який приймає відношення, виробляє і є .merge. (A || B) && (C || D) може вироблятися Post.where (a) .or (Post.where (b)). Merge (Post.where (c) .or (Post.where) (d )))
Сіїм Лізер

2
@MathieuJ. Це ActiveRecord :: відношення # злиття. api.rubyonrails.org/classes/ActiveRecord/…
Сіїм Лізер

13

Для використання цього ORзапиту нам не потрібно чекати рейок 5 . Ми також можемо використовувати його rails 4.2.3. Існує перенести тут .

Дякуємо Еріку-Го за дорогоцінний камінь, де-або , Тепер ми можемо додати цю ORфункціональність, >= rails 4.2.3також використовуючи цей самоцвіт.


6

(Просто доповнення до відповіді К.М. Ракібул Іслам.)

Використовуючи сфери застосування, код може стати гарнішим (залежно від очей, які дивляться):

scope a,      -> { where(a) }
scope b,      -> { where(b) }

scope a_or_b, -> { a.or(b) }

5

Мені потрібно було зробити (A && B) || (C && D) || (E && F)

Але в 5.1.4нинішньому стані Рейлівс це стає занадто складним, щоб здійснити його з ланцюгом Arel. Але я все ж хотів використовувати Rails для отримання якомога більшої кількості запитів.

Тому я зробив невеликий злом:

У своїй моделі я створив приватний метод під назвою sql_where:

private
  def self.sql_where(*args)
    sql = self.unscoped.where(*args).to_sql
    match = sql.match(/WHERE\s(.*)$/)
    "(#{match[1]})"
  end

Далі в своєму діапазоні я створив масив для утримання АБО

scope :whatever, -> {
  ors = []

  ors << sql_where(A, B)
  ors << sql_where(C, D)
  ors << sql_where(E, F)

  # Now just combine the stumps:
  where(ors.join(' OR '))
}

Який дасть очікуваний результат запиту: SELECT * FROM `models` WHERE ((A AND B) OR (C AND D) OR (E AND F)).

І тепер я можу легко поєднувати це з іншими областями тощо без будь-яких протиправних АБО.

Краса полягає в тому, що мій sql_where приймає нормальні аргументи, де-clause: sql_where(name: 'John', role: 'admin')генерує (name = 'John' AND role = 'admin').


Я думаю, ви можете використовувати .mergeяк еквівалент &&, і побудувати належне дерево, щоб захопити ваші парени. Щось на кшталт ... (scopeA.merge(scopeB)).or(scopeC.merge(scopeD)).or(scopeE.merge(scopeF)), якщо припустити, що кожна з областей виглядає приблизно такModel.where(...)
nar8789

Перевірте це, перш ніж використовувати merge - github.com/rails/rails/isissue/33501
Aarthi

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.