基本

Ruby on Railsのコールバック(before_action / after_action)

Ruby on Railsのコールバックは、コントローラーのアクションが実行される前後に自動的に処理を挟み込む仕組みです。認証チェック、ログ記録、データの事前読み込みなど、複数のアクションで共通する処理をコールバックとして定義することで、コードの重複を防ぎメンテナンス性を向上させます。この記事では、コールバックの種類と実践的な使い方を解説します。

基本的な使い方

最もよく使われるのがbefore_actionです。アクションが実行される前に指定したメソッドを自動的に呼び出します。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_message

  def index
    # @messageはset_messageで既に設定済み
  end

  def show
    # @messageはset_messageで既に設定済み
  end

  private

  def set_message
    @message = "ようこそ"
  end
end

before_action :set_messageと記述すると、このコントローラーのすべてのアクションが実行される前にset_messageメソッドが呼ばれます。認証チェックやデータの事前読み込みに頻繁に使用されるパターンです。

コールバックの種類

Railsのコントローラーには3種類のコールバックがあります。

コールバック 実行タイミング 主な用途
before_action アクション実行前 認証、データの事前読み込み
after_action アクション実行後 ログ記録、レスポンスの後処理
around_action アクション実行の前後 処理時間の計測、トランザクション管理

特定のアクションに限定する

onlyオプションやexceptオプションを使って、コールバックを適用するアクションを制限できます。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :authenticate_user!, except: [:index, :show]
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  def index
    @posts = Post.all
  end

  def show
    # @postはset_postで設定済み
  end

  def edit
    # @postはset_postで設定済み
  end

  def update
    if @post.update(post_params)
      redirect_to @post
    else
      render :edit
    end
  end

  def destroy
    @post.destroy
    redirect_to posts_path
  end

  private

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

  def authenticate_user!
    redirect_to login_path unless current_user
  end
end

onlyは指定したアクションでのみ実行し、exceptは指定したアクション以外で実行します。上記の例では、indexshowは認証不要で、それ以外のアクションには認証が必要です。

after_actionの使い方

after_actionはアクションの実行後に処理を行います。ログの記録やレスポンスヘッダーの追加などに使います。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  after_action :log_access

  private

  def log_access
    Rails.logger.info "#{controller_name}##{action_name} accessed by #{current_user&.name || 'Guest'}"
  end
end

around_actionの使い方

around_actionはアクションの前後を包み込むように処理を実行します。yieldでアクション本体を実行します。

app/controllers/reports_controller.rb
class ReportsController < ApplicationController
  around_action :measure_time, only: [:generate]

  def generate
    @report = Report.create_monthly_report
  end

  private

  def measure_time
    start_time = Time.current
    yield  # ここでアクション本体が実行される
    duration = Time.current - start_time
    Rails.logger.info "処理時間: #{duration}秒"
  end
end
ポイント

before_actionredirect_torenderを実行すると、後続のアクション本体はスキップされます。これを利用して認証チェックを実装すると、未認証のユーザーがアクションを実行するのを防げます。

注意

コールバックを多用しすぎると、処理の流れが追いにくくなります。コールバックチェーンが長くなる場合は、Service Objectなどのデザインパターンを検討してください。

まとめ

  • before_actionはアクション実行前、after_actionは実行後、around_actionは前後に処理を挟む
  • onlyexceptで適用するアクションを制限できる
  • 認証チェックやデータの事前読み込みはbefore_actionの代表的な使い方
  • around_action内ではyieldでアクション本体を実行する
  • before_action内でredirect_toするとアクション本体はスキップされる
  • コールバックの多用は避け、処理の流れを追いやすく保つ