web-dev-qa-db-fra.com

Rails 5: ActiveRecord OR question

Comment faites-vous une requête or dans Rails 5 ActiveRecord? De même, est-il possible de chaîner or avec where dans les requêtes ActiveRecord?

94
K M Rakibul Islam

La possibilité de chaîner la clause or avec la clause where dans la requête ActiveRecord sera disponible dans Rails 5. Voir la discussion connexe et la demande d'extraction .

Ainsi, vous pourrez faire les choses suivantes dans Rails 5:

Pour obtenir une post avec id 1 ou 2:

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

Quelques autres exemples:

(A && B) || C:

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

(A || B) && C:

    Post.where(a).or(Post.where(b)).where(c)
192
K M Rakibul Islam

Nous n'avons pas besoin d'attendre que Rails 5 utilise cette requête OR. Nous pouvons également l'utiliser avec Rails 4.2.3. Il y a un backport ici .

Merci à Eric-Guo pour gem où-ou , nous pouvons maintenant ajouter cette fonctionnalité OR dans >= Rails 4.2.3 en utilisant également ce joyau.

12
Dipak Gupta

Je devais faire un(A && B) || (C && D) || (E && F)

Mais dans l'état actuel de Rails 5.1.4, cela est trop compliqué à accomplir avec Arel ou la chaîne . Mais je voulais tout de même utiliser Rails pour générer autant de requêtes que possible.

Alors j'ai fait un petit bidouillage:

Dans mon modèle, j'ai créé une méthode private appelée sql_where:

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

Suivant dans ma portée, j'ai créé un tableau pour contenir les blocs

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 '))
}

Ce qui produira le résultat de requête attendu: SELECT * FROM `models` WHERE ((A AND B) OR (C AND D) OR (E AND F)).

Et maintenant, je peux facilement combiner cela avec d'autres portées, etc., sans aucun OU injustifié.

La beauté est que mon sql_where prend les arguments normaux de la clause where: sql_where(name: 'John', role: 'admin') générera (name = 'John' AND role = 'admin').

4
mtrolle

(Juste un ajout à la réponse de K M Rakibul Islam.)

En utilisant des oscilloscopes, le code peut devenir plus joli (en fonction de l'aspect des yeux):

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

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

Rails 5 peut utiliser la clause or avec where.

User.where(name: "abc").or(User.where(name: "abcd"))
0
Foram Thakral