表参道.rb #38 〜Railsアンチパターン〜 でやった LT です。 https://omotesandorb.connpass.com/event/98377/
元ネタ: http://osa.hatenablog.com/entry/good-bye-before-action-setter
before action setter いる?2018-09-06 表参道.rb #381
View Slide
自己紹介• @s_osa_• OSA Shunsuke• Cookpad Inc.• 技術部 ユーザー・決済基盤グループ• Rails に対しては愛憎相半ばする複雑な気持ちを抱いている2
話すこと• before action setter って必要?• 多くの場合、いらないのでは?3
before action setter名前がないといろいろ不便なので、勝手に before actionsetter と呼んでいますが、要は scaffold でも生成されるこいつ。class HogesController < ApplicationControllerbefore_action :set_hoge, only: %i[show]privatedef set_hoge@hoge = Hoge.find(params[:id])endend4
つらい理由5
変数の初期化・代入を目的としたメソッドset_* を呼ぶと、メソッド呼び出し側にインスタンス変数が増えるという重大かつ直感的でないな副作用がある。普段コードを書くときにdef set_message@message = 'Hello'endset_messageみたいなことをする人はまずいないはず。6
自明でない順序依存性が発生しがちはじめはシンプルだった before action setter も、機能追加などをしていくうちに、いつの間にかbefore_action :set_hogebefore_action :set_fugabefore_action :set_foo # set_bar ΑΓઌʹ࣮ߦ͢Δ͜ͱʂʂbefore_action :set_barのようなことになりがち。7
action の関心がわかりにくいRails の controller におけるインスタンス変数は view で参照する変数であり、レスポンスを組み立てるために必要なものが入っている。インスタンス変数が暗黙的に代入されると、その actionの関心が何なのかが少なくともパッとはわからない。8
じゃあ、どう書くか9
シンプルなときそのまま書けば良い。class HogesController < ApplicationControllerdef show@hoge = Hoge.find(params[:id])enddef edit@hoge = Hoge.find(params[:id])end# ...end10
複雑・重要な絞り込みがあるとき具体的には、複雑だったり重要だったりする絞り込みを行なっていて、その重複を避けたい場合。そういうときは set_* じゃなく find_* する。class HogesController < ApplicationControllerdef show@hoge = find_hoge(params[:id])endprivate# @param id [String]# @return [Hoge]def find_hoge(id)Hoge.very.complex.condtion.find(id)endend11
順序依存性があるとき複数の before action setter の間に順序依存性があったケースでは依存を明確にして管理するために引数として渡す。class HogesController < ApplicationControllerdef show@hoge = find_hoge(params[:id])@fuga = find_fuga(@hoge)endprivate# @param id [String]# @return [Hoge]def find_hoge(id)Hoge.very.complex.condtion.find(id)end# @param hoge [Hoge]# @return [Fuga]def find_fuga(hoge)hoge.fugas.very.important.condition.firstendend12
before action を使うべきとき13
認証・検証など• action が呼ばれる際に満たしておく事前条件のようなものが存在し、その条件を満たさないときは action を実行しないような類のもの。•authenticate_*! とか verify_*! みたいなメソッド名が多い。• 別の言い方をすると、before_action の旧名であるbefore_filter という名前がしっくり来る感じのやつ。•setter じゃないことも多いが、認証・検証後に set することもありがち。14
横断的に使用される変数など• 典型的には set_current_user のようなもの。• そのアプリケーションで横断的に使われる変数などの初期化・代入。•広く使われるものであれば、そのアプリケーションを開発する人の基礎知識とすることに妥当性が生まれる。• 横断的に使用されるという性質上、この種の before actionsetter は ApplicationController やAdmin::BaseController のような場所に定義される。15
まとめ16
まとめ• before action setter って必要?• 多くの場合、いらない。• Rails とはいい感じに折り合いをつけて付き合っていきたい。17
Thank You!18