You are developing your first Rails app, which is most likely a Blog - we all have been there :).
At some point, you end up with a controller created by scaffold, which looks more or less, like this:
class PostsController < ApplicationController
before_action :set_post, only: %i[ show edit update destroy ]
# GET /posts or /posts.json
def index
@posts = Post.all
end
# GET /posts/1 or /posts/1.json
def show
end
# GET /posts/new
def new
@post = Post.new
end
# GET /posts/1/edit
def edit
end
# (...) update create and destroy actions are hidden
# for the sake of readability
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@post = Post.find(params[:id])
end
end
Rails generated set_post
method, and even tells you to Use callbacks to share common setup or constraints between actions.
The code is DRY as it can be, you have a nice looking before_action
, so it must be the famous Rails way of doing things - and it is.
However some developers (including me) are writing code in a different way.
Why?
Let's assume, that we stick to Filters (it is the official name of this feature despite the fact, that scaffold is calling it callback) - after implementing additional functionalities we can end up with something like this:
class PostsController < ApplicationController
before_action :set_post, only: %i[ show edit update destroy ]
before_action :set_user, only: %i[ edit update ]
before_action :check_admin, only: :destroy
after_action :send_email, only: %i[ update destroy ]
# GET /posts or /posts.json
def index
@posts = Post.all
end
# GET /posts/1 or /posts/1.json
def show
end
# GET /posts/new
def new
@post = Post.new
end
# GET /posts/1/edit
def edit
end
# (...)
end
Reading edit
action has just become a bit harder, because you ended up with an empty action, which is in fact does quite a lot of things.
So in order to understand what is going on there you have to jump back and forth between the filters. And this is relatively simple action - you can image what happens, when the app grows.
What is the 'right' way?
Alternative approach is actually really simple - just call the method inside the action. That's it.
Then you end up with code like this:
class PostsController < ApplicationController
# GET /posts or /posts.json
def index
@posts = Post.all
end
# GET /posts/1 or /posts/1.json
def show
set_post
end
# GET /posts/new
def new
@post = Post.new
end
# GET /posts/1/edit
def edit
set_post
end
# (...) update create and destroy actions are hidden
# for the sake of readability
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@post = Post.find(params[:id])
end
end
Now, at first glance at edit
or show
action you know which method is called.
Got it - let's forget about Action Filters
Actually, not really - they are used for authentication
/ authorization
- you will more than once see code like this, especially when working with devise
gem:
class PostsController < ApplicationController
before_action :authenticate_user!
end
Wrap up
If you are not dealing with authentication
/ autorization
try avoiding using Action Filters (referred by some as ''callbacks'') - they make code harder to read.