How do you do an or
query in Rails 5 ActiveRecord? Also, is it possible to chain or
with where
in ActiveRecord queries?
The ability to chain or
clause along with where
clause in ActiveRecord
query will be available in Rails 5. See the related discussion and the pull request.
So, you will be able to do the following things in Rails 5:
To get a post
with id
1 or 2:
Post.where('id = 1').or(Post.where('id = 2'))
Some other examples:
(A && B) || C:
Post.where(a).where(b).or(Post.where(c))
(A || B) && C:
Post.where(a).or(Post.where(b)).where(c)
Post.where(a).or(Post.where(b)).where(Post.where(c).or(Post.where(d)))
this should create (a || b) && (c || d) –
Kelton ArgumentError: Unsupported argument type: #<MyModel::ActiveRecord_Relation:0x00007f8edbc075a8> (MyModel::ActiveRecord_Relation)
–
Windjammer merge
coming from ? if its Array#merge
that does not work for me, as I want a single query to be executed. and also being able to pass the whole thing as a relation –
Stepchild (Just an addition to the answer by K M Rakibul Islam.)
Using scopes, the code can become prettier (depending on the eyes looking):
scope a, -> { where(a) }
scope b, -> { where(b) }
scope a_or_b, -> { a.or(b) }
I needed to do a (A && B) || (C && D) || (E && F)
But in Rails 5.1.4
's current state this get's too complicated to accomplish with the Arel or-chain.
But I still wanted to use Rails to generate as much of the query as possible.
So I made a small hack:
In my model I created a private method called sql_where
:
private
def self.sql_where(*args)
sql = self.unscoped.where(*args).to_sql
match = sql.match(/WHERE\s(.*)$/)
"(#{match[1]})"
end
Next in my scope I created an array to hold the OR's
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 '))
}
Which will produce the expected query result:
SELECT * FROM `models` WHERE ((A AND B) OR (C AND D) OR (E AND F))
.
And now I can easily combine this with other scopes etc. without any wrongful OR's.
The beauty being that my sql_where takes normal where-clause arguments:
sql_where(name: 'John', role: 'admin')
will generate (name = 'John' AND role = 'admin')
.
.merge
as the equivalent of &&, and build a proper tree to capture your parens. Something like... (scopeA.merge(scopeB)).or(scopeC.merge(scopeD)).or(scopeE.merge(scopeF))
, assuming each of the scopes looks something like Model.where(...)
–
Pernickety Rails 5 has ability for or
clause with where
.
For Example.
User.where(name: "abc").or(User.where(name: "abcd"))
© 2022 - 2024 — McMap. All rights reserved.