Ruby on Rails Explained
before_action

Jul 20, 2018

When writing controllers in Ruby on rails, using before_action (used to be called before_filter in earlier versions) is your bread-and-butter for structuring your business logic in a useful way. It's what you want to use to "prepare" the data necessary before the action executes.

The action methods or blocks given the the before_action will execute in the order they where called, meaning in the following scenario, the method authorize_user will execute first, followed by find_post and finally the controller action will execute (which in this example is the show method).

class PostsController < ApplicationController
  before_action :authorize_user
  before_action :find_post

  def show
    # ...
  end

  private

  def authorize_user
    # ...
  end

  def find_post
    # ...
  end
end

An important thing to note is that the methods queued up with before_action can halt the execution at any time and return a response by calling any of the controller methods that generate a response, i.e. render, redirect, head, etc.

Take the following scenario where if there is no Post matching the :id param, then it will call the render method with a specific template and status code and as a result, the controller action show will never execute. By the same logic, we can be sure that if the controller action show is executed, then there must be a @post instance variable present for us to use in the action and views.

def find_post
  @post = Post.find params[:id]
rescue ActiveRecord::RecordNotFound => e
  render template: 'not_found', status: :not_found
end

Another thing to keep in mind is that before_action methods can use anything that previous methods have prepared (i.e. instance variables). In the following scenario we require a current user to be present, otherwise we return a 401 access denied response. And after that, we only allow a post to be shown if it is associated with said user.

def authorize_user
  @current_user = bearer_token.present? && User.find_by token: bearer_token
  render template: 'access_denied', status: :access_denied if @current_user.nil?
end

def find_post
  @post = @current_user.posts.find params[:id]
rescue ActiveRecord::RecordNotFound => e
  render template: 'not_found', status: :not_found
end

 # Helper method to retrieve the Bearer token from Authorization header
def bearer_token
  regex = /^Bearer /
  header  = request.headers['Authorization']
  header.gsub(regex, '') if header&.match(regex)
end

These are just some ways in which you can implement before_action methods.

Happy coding!