Snippet: using 'inherited' to set filters in controllers

Posted by trevor Fri, 26 May 2006 22:51:37 GMT

One of my apps has a set of controllers in an ’/admin’ directory. They all must have a :login_required before_filter and they all must define an authorized? method that checks if the current user is an administrator.

For a couple of reasons the idea of having a special “AdminController” which everything under ’/admin’ would inherit from (and that set up the filter and authorized? method) kind of irked me.

First, there was the name clash – AdminController becomes ‘admin’ in routes and that clashes with my directory called ‘admin’, so I’d have to choose a name like “AdminBaseController” or some-such. Blech.

Second, I just didn’t like the extra file for the base controller. Call me picky, I can take it.

What I wanted was a way to say “if the controller is in the /admin directory then it needs this filter and this method”.

Class#inherited to the rescue. Here’s what I put in /app/controllers/application.rb:

# For all controllers in the 'Admin' namespace we set
# the login_required before_filter and define an authorized?
# method that checks user.is_administrator? 
def self.inherited(subclass)
  # call super first - otherwise any before_filters we add are lost
  super
  if subclass.name.split('::').first == 'Admin'
    subclass.before_filter :login_required
    subclass.send(:define_method, :authorized?, Proc.new {|user| user.is_administrator?})
    subclass.send(:protected, :authorized?)
  end
end

This is fine for my present needs. If controllers under /admin start to need any more shared behavior I’ll just bite the bullet and do the AdminBaseController thing – but for now this is clean and works.

Posted in code | no comments