In my my controllers I am restricting access to features based on the users assigned price plan, which is an integer, mappable to a label such as ‘Gold’, ‘Silver’, ‘Bronze’.

As well as providing autherisation at the controller layer, where it belongs, I also wish to enforce this at the model layer. This gives me defense in depth and will also alert me to holes in the autherisation at the controller level where testing dare not tread.

I have a YAML file which has a list of methods (the key) and minimum price plan (the value). At the top of my model I specify which methods I want to protect. At the bottom of model I then alias each method and check the YAML file to make sure the price plan is sufficient, if not I raise an exception, otherwise I call the original method.

class Account

  RestrictedMethods = %w(enable_logging backup)
  def enable_logging
  # do something
  def backup
  # do something

  def allow?(action)
    YAML.load(File.join(RAILS_ROOT, 'config', 'price_plan.yml'))[action.to_s].to_i >= price_plan

  RestrictedMethods.each do |method_name| 
      str_id = "__#{method_name}__hooked__"
      unless private_instance_methods.include?(str_id)
        alias_method str_id, method_name       
        private str_id                          
        define_method method_name do |*args|    
          raise PricePlanRestrictedException unless allow? method_name
          __send__ str_id, *args  # Invoke backup

The YAML file, price_plan.yml, looks like this:

backup: 5
enable_logging: 10            

This was largely inspired by the following post: