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!