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
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.
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