Created
July 23, 2008 15:45
-
-
Save joshuaclayton/1792 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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