Rails skip_before_action callback ignores conditional

Before action callback in Rails has support to add conditions like if and unless. The callback is executed only if the conditions evaluate to true. But, skip_before_action callback does not support conditionals. In this article we will learn how to skip certain action based on some condition.

before_action callback

As, before_action callback supports conditional. Let’s say, we have a ProductsController as given below.

class ProductsController < ApplicationController
  def index
  end
end

Now, let’s say, we want to run some code before index action based on some condition.

class ProductsController < ApplicationController

  before_action :execute_this, if: :this_is_true?
  
  def index
  end
  
  private
  
  def execute_this
    # Some before action condition to execute
  end
    
  def this_is_true?
    Rails.logger.debug "This is being executed before #{params[:action]}"
    true
  end
end

this_is_true method will be executed before every action of the controller. As, the method returns true, the controller action will get executed.

skip_before_action callback

skip_before_action callback supports callbacks (methods) to be skipped. It supports two options.

  • only - The callback should be run only for this action.
  • except - The callback should be run for all actions except this action.

As before_action callback supports conditional options like if? and unless, people tend to assume skip_before_action would support these two conditionals. But, that’s not the case.

skip_before_action with condition (workaround)

Let’s take the same example as given above to skip before action for some condition.

It can be written as given below.

class ProductsController < ApplicationController

  skip_before_action :execute_this
  before_action :execute_this, unless: :this_is_true?

  private
  
  def execute_this
    # Some before action condition to execute
  end
    
  def this_is_true?
    Rails.logger.debug "This is being executed before #{params[:action]}"
    true
  end

end
Interpretation and conclusion
  • execute_this callback will be skipped by default.
  • execute_this callback will be execute if this_is_true? returns false.

In order to achive conditional on skip_before_action, add the negative conditional on before_action. Provided skip_before_action is added before before_action.