This is great, and I wouldn't have seen the possibilities if you hadn't
explained it in code!

Thanks!

-Tim

On Tue, Oct 19, 2010 at 5:28 PM, Aaron Patterson <[email protected]
> wrote:

> On Tue, Oct 19, 2010 at 04:16:33PM -0500, Tim Morgan wrote:
> > Sure!
> >
> > Here is the updated patch:
> >
> https://rails.lighthouseapp.com/projects/8994/tickets/1812/a/727956/allow-default_scope-to-accept-a-proc2.patch
>
> Thanks!  I've applied it and extended it a little bit so that
> default_scope will take any object that responds to "call".
>
> I'll show some code, then try to explain the benefits.  This is now
> possible:
>
>  class AuthorFilter < Struct.new(:klass, :author_id)
>    def call
>      klass.where(:author_id => author_id)
>    end
>  end
>
>  class AmazingPost < ActiveRecord::Base
>    self.table_name = 'posts'
>    default_scope AuthorFilter.new(self, 2)
>  end
>
> The Object form does not need to save binding like the lambda form does.
>  This
> can lead to less memory usage and help curb "leaking objects".
>
> Because we can use objects, it allows our default scopes to contain more
> logic:  we can actually break up functionality to other methods.  For
> example:
>
>  class AuthorFilter < Struct.new(:klass, :some_value)
>    def calculate_id
>      ... do som complex logic to figure out the id ...
>    end
>
>    def call
>      klass.where(:author_id => calculate_id)
>    end
>  end
>
> We can even use modules or subclasses to extend our logic.  For example:
>
>  module BodyFilter
>    def call
>      super.where(:body => 'hello')
>    end
>  end
>
>  class AuthorFilter < Struct.new(:klass, :author_id)
>    def call
>      klass.where(:author_id => author_id)
>    end
>  end
>
>  class AmazingPost < ActiveRecord::Base
>    self.table_name = 'posts'
>    # Produces: WHERE author_id = 2 AND body = 'hello'
>    default_scope AuthorFilter.new(self, 2).extend(BodyFilter)
>  end
>
> Finally, we can more easily test any complex logic we need in this
> filter:
>
>  class FilterTest < Test::Unit::TestCase
>    class DreamCatcher
>      attr_reader :wheres
>      def initialize; @wheres = []; end
>      def where(arg); @wheres << arg; end
>    end
>
>    def test_appropriate_where_clause
>      dc = DreamCatcher.new
>      AuthorFilter.new(dc, 2).call
>      assert_equal([{:author_id => 2}], dc.wheres)
>    end
>  end
>
> I'd like to see the rest of our scope methods to allow arbitrary objects
> that respond to `call` for the above reasons.  :-)
>
> --
> Aaron Patterson
> http://tenderlovemaking.com/
>

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-core?hl=en.

Reply via email to