Rails: Multiple default scopes for ActiveRecord

Default scopes were introduced in Rails 2.3 to allow a default set of options to be applied to any find methods. The common example is to always order a set of results by a given column, e.g:

class Post < ActiveRecord::Base
  # Any calls to Post.find will automatically have the default :order option merged into them
  # Post.find(:all)
  # => SELECT * FROM "posts" ORDER BY "created_at DESC";
  default_scope :order => "created_at DESC"
end

Unlike named_scopes (which I am finding more and more useful every day), I found that default scopes cannot be combined when I tried to use the acts_as_revisable and is_paranoid plugins together:

class Post < ActiveRecord::Base
  acts_as_revisable
  is_paranoid
end

It seems the default scope declared in is_paranoid overrides that of acts_as_revisable. Post.find(:all) will therefore return every revision of Post rather than just the current revision. You can check this out by reversing the plugin order:

class Post < ActiveRecord::Base
  is_paranoid
  acts_as_revisable
end

Now, Post.find(:all) will return only current revisions, but will include any destroyed posts as the acts_as_revisable default scope overrides is_paranoid!

A Solution

This post and code snippet shows a method for declaring multiple default scopes on a model. I've not yet tried out the code, though, as one of the commenter's was kind enough to forkis_paranoid and modify it to merge any existing default scopes. With this forked plugin, Post can be scoped correctly by both plugins.

The fork is available at http://github.com/grioja/is_paranoid/tree/master.

But... is_paranoid is depracated

I noticed that the original is_paranoid plugin has ceased development, so I'm not sure if I'll continue to use it, although It's a neat little plugin, and has several forks.

The underlying problem, though, of ActiveRecord allowing only one default_scope to be declared, is something that I'm bound to come up against in the future, so it's handy to know there is a workaround at least until Rails includes the functionality.

As an aside, Rich Cavanaugh, the developer of acts_as_revisable, has pointed out that the plugin includes some basic is_paranoid functionality already (see Rich's reply to my original ramblings):

class Post < ActiveRecord::Base
  acts_as_revisable :on_delete => :revise
end

Do you use default_scope? Do you find the single scope a limitation, or do you rely on named scopes? Feel free to discuss in the comments.

« Previous Post

avatar

Chris Blunt

Plymouth Software

Devon, England

twitter.com/cblunt

github.com/cblunt

 

facebook.com/cbluntuk

flickr.com/photos/cblunt