Hi all!
I’ve googled all over and I couldn’t find anything about chaining scopes with OR instead of the default AND.
I have an Asset model with the following scopes:
class Asset < ActiveRecord::Base
(…)
scope :find_in_coverage, lambda { where(‘timestamp(assets.found_at) >= ?’, Asset.found_at_limit) }
scope :find_unknown_in_coverage, where(‘assets.asset_type_id IS NULL’).find_in_coverage
scope :find_known_missing, lambda { where(‘assets.found_at < ? AND assets.asset_type_id IS NOT NULL’, Asset.found_at_limit) }
end


I would like to create another scope (“find_visibles”) which is the OR of “find_in_coverage” and “find_known_missing” scopes, like that:
scope :find_visibles, find_in_coverage.find_know_missing
The problem is that this method chain uses AND to concatenate WHERE clauses. I need this clauses to be concatenated using OR instead.
How can I do that?
Thanks in advance,
Gustavo Honorato
AFAIK, something like this should work:
def find_visibles
find_in_coverage | find_known_missing
end
To add to that, if you want to construct complex queries, you should have a look at arel.
The problem of the first solution is that “find_in_coverage | find_known_missing” combined that way does not return a scope. It returns two arrays each and applies | operator on the result. See: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-7C
I’ve looked arel docs (in fact, I just found poor docs). Can you please point me where in docs is explaining how I can construct such query?
Thanks for you attention,
Gustavo
The problem of the first solution is that “find_in_coverage | find_known_missing” combined that way does not return a scope. It returns two arrays each and applies | operator on the result. See: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-7C
I’ve looked arel docs (in fact, I just found poor docs). Can you please point me where in docs is explaining how I can construct such query?
Have you read the README for arel? (https://github.com/rails/arel)
"The OR operator works like this:
users.where(users[:name].eq(‘bob’).or(users[:age].lt(25)))"
I don’t think you can do this through scopes, so working arel is the best alternative, but it may just be more hassle than you need. If you want a really hacky solution, I’ve done stuff like this in the past:
recipe_query = Recipe.where(“pastry_id = 1”).where(“filling_id = 1”)
Recipe.where(recipe_query.where_values.join(" OR "))
That generates:
SELECT “recipes”.* FROM “recipes” WHERE (pastry_id = 1 OR filling_id = 1)
That might give you some ideas. It goes without saying that this is some hacky stuff you’re getting into, so I’d tread carefully!
Jeremy Walker
http://www.ihid.co.uk
try
escopo: find_visibles, lambda { find_in_coverage.find_know_missing}
@Rogerio: This way the scopes are merged with AND not OR
@Jeremy: I’ve read README and I haven’t found a way to join scopes with OR, as you mentioned. The only way I found is to join attributes with OR, not scopes. I’ve tried that hack (where_clauses.join(‘OR’)) before too. The problem is that, for some reason, it don’t work when we use the scope chained with a association.
I’ve googled a lot and I found a lot of people complaining about this missing feature. I’m a big fan of Rails, but it is a pitty that Rails doesn’t give any simple way to do that. I really want to avoid that, but the best solution that I can see is to duplicate the code of the first two scopes on find_visibles.
Thanks,
Gustavo
Hi Gustavo
Coincidentally, I was recently doing something similar. Older versions of rails used to evaluate my previous solution using " | " to an ActiveRelation. When this stopped I dont know, or maybe I am just mistaken. In any case, I finally settled on using the squeel gem, the arel docs, I agree are quite horrible.
There are examples on ‘OR’ queries with squeel on the github readme.
U try ?
escopo: find_visibles, lambda { find_in_coverage|find_know_
missing}