What order do before filters occur in?

11.2k views Asked by At

What order do before filters occur in? Specifically, what order do the before_action filters occur in, in regards to inheiritance? For example, will this work:

class A < ActionController::Base
  before_action :set_user

  def set_user
    @user = something
  end
end

class B < A
  before_action :set_post

  def show
    render @post
  end

  def set_post
    @post = @user.posts.first
  end
end

Will B#show work? What are the rules for filter order for future reference? I can't find any of this in the Rails documentation.

3

There are 3 answers

3
deefour On BEST ANSWER

I suggest taking a look at the source code and API Docs on filters.

The default ordering should be

  1. :set_post
  2. :set_user

I think if you wanted to push :set_user to the top of the stack you could change the line in A to

prepend_before_action :set_user

Also worth pointing out, this isn't the only question on the topic; there are others here on SO.


As for your specific situation, it looks like you'll need to change A as I mentioned above in order to have @user be assigned by the time set_post in B runs.


As of 4.2.6 (probably changed in an earlier version), the ordering is now parent before child:

  1. :set_user
  2. :set_post
1
Felix Livni On

Yes, your code will work as intended.

The before_filters on the derived class (B) are called before the before_filters on the base class (A). So the order of the methods called are:

  1. set_user()
  2. set_post()
  3. show()

Also note, after_filters are called in reverse order, the most derived first.

0
kid_drew On

The accepted answer is no longer true as of Rails 4.2.6. It was probably changed earlier, but that's the version I'm on right now.

Parent filters are now called before child filters, so the ordering will now be:

  1. :set_user
  2. :set_post

And, if you think about it, that ordering really makes more sense. As previously said, if you need the child to call the filter before the parent, you need to use prepend_before_action.