結論
複数ある場合は、下から順番にprepend_before_actionが実行される
きっかけ
controllerでbefore_actionを複数個書くと当然ファイルの上から実行されます。
prepend_before_action を複数個定義する要件がありbefore_actionと同じ感覚で実行されて欲しい順に記載したのですが、意図した順番とは逆の結果になってしまいました。
調査
少なくとも自分が調べた限り直接的なドキュメントはなかったのでソースコード読みました。
prepend_before_actionの定義は以下のソースコードです。
...途中省く [:before, :after, :around].each do |callback| define_method "#{callback}_action" do |*names, &blk| _insert_callbacks(names, blk) do |name, options| set_callback(:process_action, callback, name, options) end end define_method "prepend_#{callback}_action" do |*names, &blk| _insert_callbacks(names, blk) do |name, options| set_callback(:process_action, callback, name, options.merge(prepend: true)) end end define_method "skip_#{callback}_action" do |*names| _insert_callbacks(names) do |name, options| skip_callback(:process_action, callback, name, options) end end
定義のところだけ抜き出します。
define_method "prepend_#{callback}_action" do |*names, &blk| _insert_callbacks(names, blk) do |name, options| set_callback(:process_action, callback, name, options.merge(prepend: true)) end end
prependの時はset_callback
メソッドのオプションとして、prepend: true
を追加しているみたいです。
続いてset_callback
メソッドのドキュメントを見てみます。
:prepend
- Iftrue
, the callback will be prepended to the existing chain rather than appended.
の記載があります。
既にあるcallbackチェーンの後ろに追加するのではなく先頭に付ける、と書いてありました。
つまり、prepend_before_action を複数個定義すると、 ファイルの上からcallbackチェーンの先頭に追加されていくので、実行時は一番先頭である最後のprepend_before_actionが実行されるようです。
つまりこんな感じになります。
class SomeController < ApplicationController prepend_before_action :first_prepend prepend_before_action :second_prepend def hoge_action # ... end private def first_prepend puts "First" end def second_prepend puts "Second" end end
この場合結果としては、こうなりました。
Second First