Today's (un)feature covers the oft-abused and misunderstood with_scope method. The excellent err.the_blog had a post on how you should be using with_scope (yes, only use it in your ActiveRecord models, not in your controllers or filters). Yes that blog post may have been written a long time back but it's still applicable to Rails 2.0.

With Rails 2.0, the with_scope method is now protected, meaning that you can no longer use it in your controllers (unless you use the #send(:with_scope), or #send!(:with_scope) in Ruby 1.9). I'm not even going to show you how you could use it in your controllers since you really shouldn't (unless you know what you are doing).

Here's what with_scope allows you to do:

class SiteOwner < ActiveRecord::Base

  # Returns list of distinct active sites.
  def active_sites(*args)
    with_scope :find => { :select => 'DISTINCT(site)', :conditions => { :active => true } } do
      find(*args).collect(&:site)
    end
  end
end

And even better example, stolen from the err.the_blog post mentioned above, is re-using scopes:

class Movie < ActiveRecord::Base
  def self.find_playing(*args)
    with_playing do
      find(*args)
    end
  end

  def self.find_playing_by_id
    with_playing do
      find_by_id(*args)
    end
  end

  def self.with_playing 
    with_scope :find => { :conditions => [ state = ? AND visible = ?, NOW_PLAYING, true ] } do 
      yield 
    end 
  end
end

I tend to use that a lot combined with method_missing magic (also from the err.the_blog post) to allow me to do things like Movie.find_playing_by_name:

def self.method_missing(method, *args, &block)
  if method.to_s =~ /^find_(all_)?playing_by/
    with_playing do
      super(method.to_s.sub('playing_', ''), *args, &block)
    end
  else
    super(method, *args, &block)
  end
end

If you prefer to get these for free, check out the the Rails scope-out plugin implements many of the ideas in the err.the_blog post.

About the contributor, Josh Peek

Josh Peek (WorkingWithRails profile) was the man behind the "protection" of with_scope. This is not Josh's greatest contribution to Rails, of course - Josh has been a very productive and active Rails contributor since the very beginning. A winner of one of the monthly Rails Hackfest, you can read up on the ever-elusive (I say "elusive" because he doesn't have a blog - it's just patch after patch after patch) Josh Peek in this post-Rails Hackfest interview.

Josh is also the man behind the deprecation and "plugin-izing" of dynamic scaffolding and pagination (yes, those are gone from Rails 2.0) among a great number of other patches and test coverage improvements. Right now, Josh appears to be working on refactoring ActionView.

Outro

Apologies for the late-on-arrival Rails 2.0 a feature a day posts, but such is life. Feature #5 follows immediately after :)