Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord Arel OR condition

How can you combine 2 different conditions using logical OR instead of AND?

NOTE: 2 conditions are generated as rails scopes and can't be easily changed into something like where("x or y") directly.

Simple example:

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

It's easy to apply AND condition (which for this particular case is meaningless):

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

But how can you produce the following query having 2 different Arel relations already available?

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

It seems (according to Arel readme):

The OR operator is not yet supported

But I hope it doesn't apply here and expect to write something like:

(admins.or authors).to_sql 
like image 838
Dmytrii Nagirniak Avatar asked Nov 02 '11 05:11

Dmytrii Nagirniak


People also ask

What does Arel SQL do?

Arel is a SQL abstraction that ActiveRecord uses to build SQL queries. Arel wraps each component of the SQL query language with Ruby objects and provides an expressive DSL for composing SQL queries. When using Arel, you're mainly interacting with tables ( Arel::Table ) and nodes ( Arel::Nodes::Node subclasses).

What is Rails Arel?

Arel is a library that was introduced in Rails 3 for use in constructing SQL queries. Every time you pass a hash to where, it goes through Arel eventually. Rails exposes this with a public API that we can hook into when we need to build a more complex query.

What is Arel Ruby?

Arel is a SQL AST manager for Ruby. It. simplifies the generation of complex SQL queries, and. adapts to various RDBMSes.

What does ActiveRecord base do?

ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending.


1 Answers

ActiveRecord queries are ActiveRecord::Relation objects (which maddeningly do not support or), not Arel objects (which do).

[ UPDATE: as of Rails 5, "or" is supported in ActiveRecord::Relation; see https://stackoverflow.com/a/33248299/190135 ]

But luckily, their where method accepts ARel query objects. So if User < ActiveRecord::Base...

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

query.to_sql now shows the reassuring:

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

For clarity, you could extract some temporary partial-query variables:

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

And naturally, once you have the query you can use query.all to execute the actual database call.

like image 159
AlexChaffee Avatar answered Oct 14 '22 08:10

AlexChaffee