Scope_out feature: default_scope
I suppose, you know the great scope_out plugin for rails. If not, go check it out, since it's really great to define DRY scoped associations. Basically, you can use scope_out to define the scoped associations within the model the scope is applied to. However, what I'm missing is a feature like a default scope that can be applied to the model and scopes the default finder.
Consider the following example where a user belongs to a group and a group has many users:
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :group
end
I want to distinguish between active and inactive users, so I added a "status" attribute that either contains 'active' or 'inactive'. Using scopeout, you can easily access all active and all inactive users via all othe models that have a hasmany :users association:
class User < ActiveRecord::Base
scope_out :active, :conditions => { :status => 'active' }
scope_out :inactive, :conditions => { :status => 'inactive' }
end
So far, that's great... You get group.users.active
and group.users.inactive
. However, next I'd like to track an additional status of a user: 'deleted'. If a user is deleted, his database record should not really be destroyed, but marked as 'deleted' in the status attribute. This would make it possible to keep a working reference to an existing record of a deleted user, e.g. in a post that this user wrote before he was deleted.
To get scoped finders for deleted and non-deleted users, you however need to add the following scope_out statements to the user model:
class User < ActiveRecord::Base
scope_out :deleted, :conditions => { :status => 'deleted' }
scope_out :non_deleted, :conditions => "status != 'deleted'"
end
Now, this works nice, however the drawback is, that you now have to watch out to use group.users.non_deleted
at any place you used group.users
before. E.g. the controller that takes care of showing a page with all users of a group probably uses group.users
to fetch the users of a group. But actually, deleted users should not be displayed by default.
Idea: default_scope
It would be great, to be able to define a default scope that applies to all finder methods that are not otherwise scoped out. E.g. like this:
class User < ActiveRecord::Base
scope_out :deleted, :conditions => { :status => 'deleted' }
default_scope :conditions => "status != 'deleted'"
end
This should result in:
group.users # get a list of users where status is not 'deleted' (default scope applied)
group.users.active # get a list of users where status is 'active' (default scope NOT applied)
group.users.find(5) # get user with id 5 (default scope NOT applied)
group.users.find(:all, :conditions => '...') # get users which match the condition (default scope NOT applied)
I'm not sure yet, if it would make sense to apply the default scope to automatic finders like find_by_name
.
I don't know how others think about this idea (comments welcome), however I'd probably like it, since it would make things easier in an application I am currently developing (which has a lot of models that have those status attribute).
Unfortunately this idea is just plain theory yet and I probably won't find time to test it until next week.
Update (2007-08-21): Actually there's a rails plugin from dvisionfactory that seems to do exactly what I was proposing here.