結論
複数ある場合は、下から順番にprepend_before_actionが実行される
きっかけ
controllerでbefore_actionを複数個書くと当然ファイルの上から実行されます。
prepend_before_action を複数個定義する要件がありbefore_actionと同じ感覚で実行されて欲しい順に記載したのですが、意図した順番とは逆の結果になってしまいました。
調査
少なくとも自分が調べた限り直接的なドキュメントはなかったのでソースコード読みました。
prepend_before_actionの定義は以下のソースコードです。
github.com
...途中省く
[: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
メソッドのドキュメントを見てみます。
api.rubyonrails.org
:prepend
- If true
, 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