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
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).
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.
Arel is a SQL AST manager for Ruby. It. simplifies the generation of complex SQL queries, and. adapts to various RDBMSes.
ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With