📘
【Rails】コントローラコールバックのifオプションと条件分岐ベタ書きの違い【before_action】
はじめに
特定の条件下でbefore_actionを設定する際、起きたエラーと疑問に思ったことを整理します。
コントローラコールバック(controller callback)は、コントローラのアクションが実行される「直前(before)」、「直後(after)」、あるいは「直前と直後(around)」に実行されるメソッドです。
起きたエラー
class BooksController < ApplicationController
if some_condition?
before_action: :foo
end
def index
end
private
def some_condition?
end
def foo
end
end
some_condition?下でのみ、各アクション実行前にfooを実行するようなコードを書きたかったのですが、以下のような関数未定義エラーが発生しました。
NameError (undefined local variable or method `some_condition?` for class BooksController)
このエラーは、以下のように記述することで解消できて、some_condition?がtrueの時のみfooをアクション直前に実行できるようになります。
before_action: :foo, if: :some_condition?
ここで、この二つの違いはどこから来ているのでしょうか。
評価のタイミング
結論としては、評価されるタイミングが異なることが主な違いのようです。
-
if: :some_condition?:コントローラのインスタンスメソッド (foo) を リクエスト毎(アクション実行直前) に呼び出すときに評価される -
if some_condition? ... end:ActiveSupport::Callbacksの仕組みを用いて、クラス読み込みのときbefore_actionがfooをコールバックチェーンに登録する際に評価される
コールバックチェーンへのメソッド登録→before_actionを実行→各アクション実行 という流れで処理が進むため、if some_condition? ... end評価時にコントローラのメソッドを参照できずエラーが起きていたようです。
class BooksController < ApplicationController
if Rails.env.development?
before_action :foo
end
end
if some_condition? ... endが(一応)使える場合もあり、Rails起動時にロードされるRails.envを用いて、:fooをコールバックチェーンに登録させる/させないような条件分岐が書けることを手元で確認しました。(BooksController._process_action_callbacksで確認)
参考
Discussion