Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshuaclayton/1792 to your computer and use it in GitHub Desktop.
Save joshuaclayton/1792 to your computer and use it in GitHub Desktop.
# class User < ActiveRecord::Base
# named_scope :active, :conditions => { :active => true }
# named_scope :with_status, lambda {|*statuses| {:conditions => ["users.status IN (?)", statuses]}}
# named_scope :joshes, :conditions => ["first_name LIKE ?", "%Josh%"]
#
# combined_scope :active_pending, lambda { active }, lambda { with_status("pending") }
# combined_scope :active_unimportant, lambda { active }, lambda { with_status("not_activated", "cancelled", "deleted") }
# # since they are real scopes, you can combine them again; in this case, with active_pending (created with combined_scope) and joshes (created with named_scope)
# combined_scope :active_pending_joshes, lambda { active_pending }, lambda { joshes }
# end
#
# Caveat
# ======
#
# You *need* to declare all combined scopes *after* the ones they reference.
# In the example above, the named_scope :with_status needs to be declared *before*
# :active_pending and :active_unimportant. In the same manner, both scopes
# :active_pending and :joshes need to be declared before :active_pending_joshes. You
# will receive NoMethodErrors if you don't heed this warning, as the method we try to call
# doesn't exist on the model until after it's defined within named_scope
module ActiveRecord
module NamedScope
module ClassMethods
def combined_scope(name, *procs, &block)
options = procs.extract_options!
procs.each do |proc|
opts = proc.bind(self).call.proxy_options
options = merge_options(options, opts)
end
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
options
when Proc
options.call(*args)
end, &block)
end
(class << self; self end).instance_eval do
define_method name do |*args|
scopes[name].call(self, *args)
end
end
end
private
def merge_options(options, extra_options)
(options.keys + extra_options.keys).uniq.each do |key|
merge = options[key] && extra_options[key]
options[key] = \
if key == :conditions && merge
merge_conditions(extra_options[key], options[key])
elsif key == :include && merge
merge_includes(options[key], extra_options[key]).uniq
else
options[key] || extra_options[key]
end
end
options
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment