Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Added initial stab at an or scope operator #6817

Closed
wants to merge 2 commits into
from

Conversation

Projects
None yet
5 participants
Contributor

loz commented Jun 21, 2012

This includes a test case and an implementation. I think I need some advice however as the only way I could replace the where clauses in a scope was to unscope, which will have killed other aspects, like having etc, so I'm happy to make changes if someone could advice.

This fixes #5545. Thanks!

Fantásticooow!!
We need it!
Thx

@loz loz commented on the diff Jun 22, 2012

activerecord/lib/active_record/relation/query_methods.rb
@@ -297,6 +297,19 @@ def where!(opts, *rest)
self
end
+ # Join scope clauses using or
+ #
+ # The passed scope is joined:
+ #
+ # User.where({ name: "Alice"}).or(User.where({ email: 'joe@example.com'}))
+ # # SELECT * FROM users WHERE name = 'Alice' OR email = 'joe@example.com'
+ #
+ def or(scope)
+ left = self.where_values.inject {|l,r| l.and(r)}
@loz

loz Jun 22, 2012

Contributor

this particular line makes the assumption that .and is always the 'join' for clauses. This is true until now, but if one had a scope with or joining to another scope with ors, they'd end up ands.

If there's an arel 'join clauses' method which would use correct concat here that would be handy. If not, a hint at where to find the concat used in the where to extract a method here to do it would be good.

@loz loz commented on the diff Jun 22, 2012

activerecord/lib/active_record/relation/query_methods.rb
@@ -297,6 +297,19 @@ def where!(opts, *rest)
self
end
+ # Join scope clauses using or
+ #
+ # The passed scope is joined:
+ #
+ # User.where({ name: "Alice"}).or(User.where({ email: 'joe@example.com'}))
+ # # SELECT * FROM users WHERE name = 'Alice' OR email = 'joe@example.com'
+ #
+ def or(scope)
+ left = self.where_values.inject {|l,r| l.and(r)}
+ right = scope.where_values.inject {|l,r| l.and(r)}
+ self.unscoped.where(left.or(right))
@loz

loz Jun 22, 2012

Contributor

I tried setting scope.where_values = [left.or(right)] however it did not persist. The only way I could do this was to clear the scope down. This kills other things unintentionally. If there's a way to do this, please can someone advise. If not, I think I need to save all the other 'values' and reassign after the scope clear.

@tenderlove

tenderlove Aug 13, 2012

Owner

Haven't tested, but would self.where_values = left.or(right) work?

@loz

loz Aug 15, 2012

Contributor

Sadly not, the assignment works, but then after the code has executed the assigned value is lost again :(

Hi Loz,
using unscope, are you disabling too, joins, selects and other scope setings? nops?

Contributor

loz commented Jun 22, 2012

Yup, this is totally NOT the solution I want, which is why I put it up for some feedback.

Member

steveklabnik commented Nov 17, 2012

Hey @loz! Do you plan to continue to work on this?

Member

steveklabnik commented Dec 15, 2012

Hey @loz! it's been a month since I've heard from you, so I'm giving this a close. If you'd like to keep up with this pull, push some more commits, and I'll gladly re-open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment