before action setter いる? / Good-bye "before action setter"

F479995c305f00405361e4b158ff225c?s=47 OSA Shunsuke
September 06, 2018

before action setter いる? / Good-bye "before action setter"

表参道.rb #38 〜Railsアンチパターン〜 でやった LT です。
https://omotesandorb.connpass.com/event/98377/

元ネタ: http://osa.hatenablog.com/entry/good-bye-before-action-setter

F479995c305f00405361e4b158ff225c?s=128

OSA Shunsuke

September 06, 2018
Tweet

Transcript

  1. before action setter いる? 2018-09-06 表参道.rb #38 1

  2. 自己紹介 • @s_osa_ • OSA Shunsuke • Cookpad Inc. •

    技術部 ユーザー・決済基盤グループ • Rails に対しては愛憎相半ばする複雑な気持ちを抱い ている 2
  3. 話すこと • before action setter って必要? • 多くの場合、いらないのでは? 3

  4. before action setter 名前がないといろいろ不便なので、勝手に before action setter と呼んでいますが、要は scaffold でも生成されるこいつ。

    class HogesController < ApplicationController before_action :set_hoge, only: %i[show] private def set_hoge @hoge = Hoge.find(params[:id]) end end 4
  5. つらい理由 5

  6. 変数の初期化・代入を目的としたメソッド set_* を呼ぶと、メソッド呼び出し側にインスタンス変数 が増えるという重大かつ直感的でないな副作用がある。 普段コードを書くときに def set_message @message = 'Hello'

    end set_message みたいなことをする人はまずいないはず。 6
  7. 自明でない順序依存性が発生しがち はじめはシンプルだった before action setter も、機能 追加などをしていくうちに、いつの間にか before_action :set_hoge before_action

    :set_fuga before_action :set_foo # set_bar ΑΓઌʹ࣮ߦ͢Δ͜ͱʂʂ before_action :set_bar のようなことになりがち。 7
  8. action の関心がわかりにくい Rails の controller におけるインスタンス変数は view で 参照する変数であり、レスポンスを組み立てるために必要 なものが入っている。

    インスタンス変数が暗黙的に代入されると、その action の関心が何なのかが少なくともパッとはわからない。 8
  9. じゃあ、どう書くか 9

  10. シンプルなとき そのまま書けば良い。 class HogesController < ApplicationController def show @hoge =

    Hoge.find(params[:id]) end def edit @hoge = Hoge.find(params[:id]) end # ... end 10
  11. 複雑・重要な絞り込みがあるとき 具体的には、複雑だったり重要だったりする絞り込みを行なっていて、その重複を避けたい場合。 そういうときは set_* じゃなく find_* する。 class HogesController <

    ApplicationController def show @hoge = find_hoge(params[:id]) end private # @param id [String] # @return [Hoge] def find_hoge(id) Hoge.very.complex.condtion.find(id) end end 11
  12. 順序依存性があるとき 複数の before action setter の間に順序依存性があったケースでは依存を明確にして管理するために引数として渡す。 class HogesController < ApplicationController

    def show @hoge = find_hoge(params[:id]) @fuga = find_fuga(@hoge) end private # @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.first end end 12
  13. before action を使うべきとき 13

  14. 認証・検証など • action が呼ばれる際に満たしておく事前条件のようなものが存 在し、その条件を満たさないときは action を実行しないような 類のもの。 •authenticate_*! とか

    verify_*! みたいなメソッド名が 多い。 • 別の言い方をすると、before_action の旧名である before_filter という名前がしっくり来る感じのやつ。 •setter じゃないことも多いが、認証・検証後に set することもあ りがち。 14
  15. 横断的に使用される変数など • 典型的には set_current_user のようなもの。 • そのアプリケーションで横断的に使われる変数などの初期 化・代入。 •広く使われるものであれば、そのアプリケーションを開発 する人の基礎知識とすることに妥当性が生まれる。

    • 横断的に使用されるという性質上、この種の before action setter は ApplicationController や Admin::BaseController のような場所に定義される。 15
  16. まとめ 16

  17. まとめ • before action setter って必要? • 多くの場合、いらない。 • Rails

    とはいい感じに折り合いをつけて付き合っていきた い。 17
  18. Thank You! 18