この記事は
- Rambulanceでやりたいことやろうとしたら若干拡張機構使う必要が出たのでメモです
やりたかったこと
- Railsの例外機構をシンプルかつ堅牢にすることができるRambulanceというgemがあります
- 便利なのですが、同一のRailsアプリの中では単一のデザイン(=layoutsファイル)しか定義することができません
- 今回URLによってデザインが諸々異なり、別のlayoutsを指定したかったです
ダメだった方法
Rambulanceが複数layoutに対応してないか?
- そもそもRambulanceは複数のlayout指定に対応していません
-
ソースも見ましたが、思いっきり単一の
@layout_name
に持っちゃってます
Rambulanceを無視してrescue_fromを書く
- 特定のコントローラに
rescue_from
を書いてしまって、処理の中で強制的にデザインの異なるエラー画面にredirectしてはどうかと考えました - が、Ramulance様はRack middlewareの根っこを抑えている神なので、rescue_fromなんていう瑣末な雑魚メソッドは完全に無視されてしまいダメでした
正解
RambulanceのCustom Exceptions Appを作成する
- READMEをよく読んでみるとCustom Exceptions Appというものの記載がありました
- ほとんど説明がないのでなんなのかは不明ながら、とりあえずそこに書いてある
$ rails g rambulance:exceptions_app
を実行してみました - すると、
app/handlers/exceptions_app.rb
にRambulanceの動きをカスタマイズできるExceptionsAppのソースが生成されました!
対応コード
- どうもこのクラスはRambulanceの本体である
Rambulance::ExceptionsApp
を拡張するもののようで、Rambulanceのエラーページ表示の前に必ず通る場所のようです - 最大のポイントは
ActionController::Base
を継承しているので、Railsの大半のメソッドが使い放題!ということです - で、下記のようなコードを書いて、URLの頭が
/other
で始まっている場合のみ、Rambulanceのエラー表示を横取りして、強制的に別レイアウトのページにredirectするようにしました
app/handlers/exceptions_app.rb
class ExceptionsApp < Rambulance::ExceptionsApp
before_action :other_layout_filter
private
def other_layout_filter
redirect_to '/other/error' if is_other_page?
end
def is_other_page?
(params[:controller]&.split('/')&.first == 'other') rescue false
end
end
- 注意点としては、このファイルの修正をしたらdevelopmentモードだとしてもRailsを再起動しなくてはなりません
終わりに
- 便利なライブラリは融通ききづらい時もあるけど、なんでもできる拡張の仕組みがあると、なんとか力技で対応できて助かりますね