From 87e3b08b45bf7da28cf3b3a80a88d151f479681d Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Sat, 7 Jun 2008 14:44:54 -0700 Subject: [PATCH] named_scope with bang --- activerecord/lib/active_record/named_scope.rb | 27 ++++++++++++++++++++++-- activerecord/test/cases/named_scope_test.rb | 8 +++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index b0c8a8b..131b3dc 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -81,6 +81,15 @@ module ActiveRecord # # expected_options = { :conditions => { :colored => 'red' } } # assert_equal expected_options, Shirt.colored('red').proxy_options + # + # + # The bang (!) can be used on a named scope to change the scope in place instead + # of returning a new scope. This is useful for building up scopes conditionally. + # + # scope = Shirt.dry_clean_only + # scope.colored!(color) if color + # + # In this example, scope is only colored if color is specified. def named_scope(name, options = {}, &block) scopes[name] = lambda do |parent_scope, *args| Scope.new(parent_scope, case options @@ -102,7 +111,7 @@ module ActiveRecord attr_reader :proxy_scope, :proxy_options [].methods.each do |m| - unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last|empty?)/ + unless m =~ /(^__|^nil\?|^send|^object_id$|^dup$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last|empty?)/ delegate m, :to => :proxy_found end end @@ -146,14 +155,26 @@ module ActiveRecord private def method_missing(method, *args, &block) - if scopes.include?(method) - scopes[method].call(self, *args) + m = method.to_s.sub(/!$/, '').to_sym + if scopes.include?(m) + if method.to_s.ends_with? '!' + replace(scopes[m].call(self.dup, *args)) + else + scopes[m].call(self, *args) + end else with_scope :find => proxy_options do proxy_scope.send(method, *args, &block) end end end + + def replace(scope) + @proxy_scope = scope.proxy_scope + @proxy_options = scope.proxy_options + @found = nil + self + end def load_found @found = find(:all) diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index d890cf7..eabe090 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -154,4 +154,12 @@ class NamedScopeTest < ActiveRecord::TestCase topics.empty? # use loaded (no query) end end + + def test_with_bang + scope = Topic.base + scope.replied! + scope.collect # force load shouldn't effect it + scope.approved! + assert_equal Topic.base.replied.approved, scope + end end -- 1.5.4.5