Post
🇬🇧 English

Les callbacks de controller en Ruby on Rails

Qu'est-ce qu'un callback et comment les utiliser efficacement dans un controller ? Voyons ça ensemble :)

Qu’est-ce qu’un callback ?

Un callback de controller permet d’indiquer à Ruby on Rails d’exécuter une méthode avant et/ou après une action (Index, Show, Create, Update, etc.) spécifique d’un controller. Voici une liste non exhaustive des callbacks disponibles dans Ruby on Rails:

  • after_action: Exécute une méthode après une action (Index, Show, Edit, etc.).
  • around_action: Exécute une méthode avant et après une action.
  • skip_before_action: N’exécute pas une méthode avant une action. Ce qui implique donc que cette méthode devait normalement être appelée avant l’action.

Vous pouvez trouver la liste de tous les callbacks possible dans la documentation de Ruby on Rails.

À noter: Les callbacks présentés dans cet article ne sont disponibles et utilisables uniquement dans les controllers. Ils ne peuvent donc pas être appelés depuis un modèle ou un PORO.

Comment utiliser un callback ?

Afin d’illustrer l’utilisation d’un callback prenons un exemple très simple: ce blog. Tous les utilisateurs connectés ou non, peuvent accéder à la liste des articles mais aussi à la visualisation d’un article (ce que vous êtes en train de faire en ce moment). Cependant, seuls les auteurs peuvent éditer et supprimer leurs articles. Si on n’utilisait pas de callback, le code ressemblerait à ça:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class PostsController < ApplicationController
  def index
    @posts = Post.all
  end

  def show
    @post = Post.find(params[:id])
  end

  def edit
    @post = Post.find(params[:id])

    redirect_to root_url if current_user != @post.author
  end

  def update
    @post = Post.find(params[:id])

    redirect_to root_url if current_user != @post.author

    @post.update!(post_params)
  end

  def destroy
    @post = Post.find(params[:id])

    redirect_to root_url if current_user != @post.author

    @post.destroy!
  end

  private

  def post_params
    params.require(:post).permit(:title, :body)
  end
end

Comme on peut s’en apercevoir on a de la redondance de code sur plusieurs actions du controller. Fort heureusement Ruby on Rails nous met disposition before_action qui nous permet d’exécuter du code avant une ou plusieurs actions. Re-écrivons notre controller en utilisant cette fois-ci le callback before_action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class PostsController < ApplicationController
  before_action :set_post, except: :index
  before_action :redirect_unless_author, except: %i[index show]

  def index
    @posts = Post.all
  end

  def show; end

  def edit; end

  def update
    @post.update!(post_params)
  end

  def destroy
    @post.destroy!
  end

  private

  def post_params
    params.require(:post).permit(:title, :body)
  end

  # Cette méthode est appelée avant toutes les actions SAUF index
  def set_post
    @post = Post.find(params[:id])
  end

  # Cette méthode est appelée avant toutes les actions SAUF index et show
  def redirect_unless_author
    redirect_to root_url if current_user != @post.author
  end
end

On remarque sur cette nouvelle version que le controller respecte le principe DRY en déplaçant la logique qui se répétait dans des méthodes séparées et en les appelant via des callbacks. Le fait d’avoir créé des méthodes qui n’effectuent qu’une seule action (set_post trouve l’article grâce à l’ID en paramètre et redirect_unless_author, redirige si l’utilisateur n’est pas l’auteur), rentre dans le cadre du design pattern (Single Responsibility Principle).

En séparant la logique en plusieurs méthodes et en utilisant les callbacks on assure une meilleure lisibilité et un code plus simple sur l’ensemble du controller.

Tous droits réservés par l'auteur.