Search code examples
ruby-on-railsproduction-environmentbefore-filter

append_before_filter in production mode


I have a controller that runs in two different "contexts" based on the logged in user (basically, a user can perform CRUD operations on their own account, and an admin user can CRUD all user accounts; the actions are the same between the contexts but the permissions are different).

In order to facilitate this, I wrote a before filter which checks the context and appends the correct context-specific permission before filter:

def ensure_logged_in
  if user_context?
    self.class.append_before_filter :authorize_user
  else
    self.class.append_before_filter :authorize_admin
  end
end

Furthermore, ensure_logged_in is only called on specific actions:

before_filter :ensure_logged_in, :only => [:show, :edit, :update]

This works perfectly fine in development mode, but once the code is in production we started experiencing weird behaviour (ie. users are being asked to log in for actions that a login should not be required; there are a couple open view actions in the controller).

My guess is that because development reloads classes each page hit, the append_before_filter call only applies for that page hit, but because production caches classes, calling append_before_filter appends it for subsequent uses of the controller. Is this a valid assumption? If so, what can I do instead?


Solution

  • My guess is that because development reloads classes each page hit, the append_before_filter call only applies for that page hit, but because production caches classes, calling append_before_filter appends it for subsequent uses of the controller. Is this a valid assumption? If so, what can I do instead?

    Your statement here is exactly correct. In production you can't be changing the filter chain on the classes like that because classes are persistant, so if you change the filter chain, that now effects every request processed by that controller class from that point forward. I would just use a normal before filter method, that calls either one of the other ones based on user_context? something like this:

    before_filter :ensure_logged_in, :only => [:show, :edit, :update]
    
    def ensure_logged_in
      if user_context?
        return authorize_user
      else
        return authorize_admin
      end
    end