before_action / before_filterのベストプラクティスはDRYより責務に目を向けること
2020/10/17追記 「beforeaction beforefilter 違い」で検索してこのページを見る方がいらっしゃるようなのですが、最近のRailsではbeforeactionという名前になっているだけで挙動に違いはありません。 Rails4でxxfilterというメソッドを xxaction という名前に変えていくという方針になり、Rails5.1で xxfilterは廃止となっています。 https://github.com/rails/rails/commit/9d62e04838f01f5589fa50b0baa480d60c815e2c
フィルターでインスタンス変数セットするのやめてほしい、と思ったのは昨日のこと。今は反省している。
before_filter / before_actionの使い方がわからなかった
昨日読んだこの記事で紹介されている、各アクションの責務でないものをフィルター化する、という考え方はとても納得の行くものだったので、今後はこの方針で使って行こうと思います。
フィルタでインスタンス変数をセットするのやめてほしいと思ってた
フィルタの使われ方としてよくあるのが、以下の処理
- actionに来る前に弾く(ログイン確認とか)
- actionで使うものの準備(actionで使うインスタンス変数をセットするとか)
マイノリティなのかもしれませんがフィルタでインスタンス変数セットするのやめてほしいと思っている人は一定数いるみたいですね。
Controllerのbefore_actionにおける インスタンス変数セットについて
自分が感じた理由は以下の2つです
どこで取得されたのかわからないインスタンス変数がうじゃうじゃいる気持ち悪さ
昨日読んだコードはインスタンス変数やらsessionやら色んなものをフィルタでセットしており、それらの出所を探すのに苦労させられました。フィルタの数がアホみたいに多く命名も適当で*1、さらに、あるものは継承元から(継承元で定義したものを継承先で使ってる)、またあるものはincludeしたmoduleから、と、一つのactionを読むために読まねばならないコードが散っていて、何でこの程度の変更でこんなにあちこち飛ばねばならんのか、という素敵さでした。
フィルタの適用順序依存の気持ち悪さ
フィルタが増えすぎたせいで、上から順に適用しないと意図しない動きになるフィルタがある。フィルタがその名の通りのフィルタなのだとしたら、その依存性って本来あるべきものなのだろうか?
徐々に目の細かいザルにかけてふるい落す、みたいな処理効率上の順位はあっていいと思うのですが、フィルタというからには、どの順番でかけても最後の結果は同じであったほうがいいんじゃないかと思うのです。
インスタンス変数をセットすることは、問題じゃない
ですが、私があげた理由からも明らかなのですが、悪いのは可読性の低いController設計になってることの方で、フィルタでインスタンス変数をセットしてること自体が悪いわけではないんですよね。
可読性の高いController設計ってどんなのよ?と言われた時に思い当たるのはこの記事
これを実行するのに私が用いているヒューリスティクスはこうです。コントローラが元々持っているRESTアクションやデフォルトの5つの機能にはないメソッドを付け加えたいと思ったら、いつだって新しいコントローラを作る。それだけでいいのです。
色んなインスタンス変数を取るフィルタが飛び交っているのは、そもそもControllerが厚すぎるのが原因で、それは各Controllerの責務がしっかり決められていないから起こっていたんですね。
責務をしっかり分ければ、自ずとフィルタも必要なControllerに散っていき、責務を切り口にすれば、actionでやるべきかフィルタでやるべきかというのもスッキリしますね。
最後に:Controllerは"Controller"って言うくらいだから。。。
こいつらの責務は、自分で何かをやることじゃなくて、割り当てられたURLを元に、処理する奴らに命令して管理すること。だから具体的な処理のロジックを持つ必要はない。さらに、自分の名前の責務から溢れるものは別のControllerに流せばいい、ということなんじゃないかな。と理解してます。
*1:get_session_dataとかそんなのが沢山ある。get,set付けるなという以前に何のdataをgetしてんのか読まないとわからない