Chain Rails scopes with OR
One of the shortcoming of scopes in ActiveRecord is the inability to chain them into an "OR" clause. Here's one way to do it. The usage isn't particularly elegant, but it gets the job done.
Concern with OR behavior
module ModelHasScopeHelpers
extend ActiveSupport::Concern
module ClassMethods
# Creates a new scope with with all where clauses joined by "OR"
# Preserves selects & orders but ignores all other query elements.
def or_scopes(*scopes)
selects = []
orders = []
wheres = scopes.map do |scope|
selects << scope.projections
orders << scope.orders
if scope.arel.where_sql.present?
scope.arel.where_sql.gsub(/\AWHERE /i, "")
else
nil
end
end
scope = where(wheres.compact.join(" OR "))
selects.flatten.each { |s| scope = scope.select(s) }
orders.flatten.each { |o| scope = scope.order(o) }
scope
end
end
end
Model
model User < ActiveRecord::Base
include ModelHasScopeHelpers
end
Usage
users = User.or_scopes(
User.where(name: "Bob"),
User.where(name: "Bobby"),
User.where(name: "Bobbie")
)
Written by Nathan Hopkins
Related protips
1 Response
Hi Nathan, this is great! I've been looking for a solution for a good while :)
Given you've been probably using this for a while, did you find any drawbacks or edge cases in which this does not work properly?
Great work BTW - annoying how the rails core team is not acknowledging how useful this is..
over 1 year ago
·
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Ruby
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#