65 votes

ActiveRecord Arel OU condition

Comment pouvez-vous combiner 2 des conditions différentes à l'aide de logique OU à la place de ET?

NOTE: 2 conditions sont générés comme des rails étendues et ne peuvent pas être facilement changé en quelque chose qui ressemble where("x or y") directement.

Exemple Simple:

admins = User.where(:kind => :admin)
authors = User.where(:kind => :author)

Il est facile à appliquer ET l'état (qui, pour ce cas particulier, est vide de sens):

(admins.merge authors).to_sql
#=> select ... from ... where kind = 'admin' AND kind = 'author'

Mais comment pouvez-vous produire la requête suivante avoir 2 différents Arel relations déjà disponible?

#=> select ... from ... where kind = 'admin' OR kind = 'author'

Il semble (selon Arel readme):

L'opérateur OU n'est pas encore pris en charge

Mais j'espère que ça ne s'applique pas ici, et s'attendent à écrire quelque chose comme:

(admins.or authors).to_sql

99voto

AlexChaffee Points 2979

ActiveRecord requêtes ActiveRecord::Relation objets (qui maddeningly ne prennent pas en charge or), pas Arel objets (qui n'). Mais heureusement, leurs where méthode accepte ARel objets de requête. Donc, si User < ActiveRecord::Base...

users = User.arel_table
query = User.where(users[:kind].eq('admin').or(users[:kind].eq('author')))

query.to_sql montre maintenant le rassurer:

SELECT "users".* FROM "users"  WHERE (("users"."kind" = 'admin' OR "users"."kind" = 'author'))

Pour plus de clarté, vous pouvez extraire quelques temporaire partielle des variables de requête:

users = User.arel_table
admin = users[:kind].eq('admin')
author = users[:kind].eq('author')
query = User.where(admin.or(author))

Et naturellement, une fois que vous avez la requête, vous pouvez utiliser query.all d'exécuter la base de données d'appel.

73voto

jswanner Points 581

Je suis un peu en retard à la fête, mais voici la meilleure suggestion que je puisse proposer:

 admins = User.where(:kind => :admin)
authors = User.where(:kind => :author)

admins = admins.where_values.reduce(:and)
authors = authors.where_values.reduce(:and)

User.where(admins.or(authors)).to_sql
# => "SELECT \"users\".* FROM \"users\"  WHERE ((\"users\".\"kind\" = 'admin' OR \"users\".\"kind\" = 'author'))"
 

9voto

Dave Newton Points 93112

De la page arel actuelle :

L'opérateur OU fonctionne comme ceci:

 users.where(users[:name].eq('bob').or(users[:age].lt(25)))
 

3voto

Olivier El Mekki Points 2793

J'ai atteint le même problème à la recherche pour un activerecord alternative à mongoid de l' #any_of.

@jswanner réponse est bonne, mais ne fonctionnera que si la où les paramètres sont un Hachage :

> User.where( email: 'foo', first_name: 'bar' ).where_values.reduce( :and ).method( :or )                                                
=> #<Method: Arel::Nodes::And(Arel::Nodes::Node)#or>

> User.where( "email = 'foo' and first_name = 'bar'" ).where_values.reduce( :and ).method( :or )                                         
NameError: undefined method `or' for class `String'

Pour être en mesure d'utiliser les chaînes et les tables de hachage, vous pouvez utiliser ceci :

q1 = User.where( "email = 'foo'" )
q2 = User.where( email: 'bar' )
User.where( q1.arel.constraints.reduce( :and ).or( q2.arel.constraints.reduce( :and ) ) )

En effet, c'est laid et que vous ne voulez pas l'utiliser sur une base quotidienne. Voici quelques - #any_of mise en œuvre que j'ai fait : https://gist.github.com/oelmekki/5396826

Il laisser faire cela :

> q1 = User.where( email: 'foo1' ); true                                                                                                 
=> true

> q2 = User.where( "email = 'bar1'" ); true                                                                                              
=> true

> User.any_of( q1, q2, { email: 'foo2' }, "email = 'bar2'" )
User Load (1.2ms)  SELECT "users".* FROM "users" WHERE (((("users"."email" = 'foo1' OR (email = 'bar1')) OR "users"."email" = 'foo2') OR (email = 'bar2')))

Edit : depuis, j'ai publié un bijou à l'aide du bâtiment OU des requêtes.

2voto

Unixmonkey Points 7947

Il suffit de faire une recherche pour votre état OR:

 scope :author_or_admin, where(['kind = ? OR kind = ?', 'Author', 'Admin'])
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X