カテゴリー:
Rails
タグ:
 Rails Filter except action only

このエントリーをはてなブックマークに追加
更新日時:
2014年01月14日(火)
作成日時:
2014年01月14日(火)

前の記事 / 次の記事

参考(関係があるのはスライドの中の一部): Smell in Rails Apps (in Sapporo RubyKaigi03)

Railsのコントローラーのフィルターオプションで、only: とか except: とか書けるけど、
only: と except: の使い分けを説明しろって言われると忘却してるっていうか、
覚えてるんだけど、プチフリーズするので自分の使い分けメモ。

結論を先に

  • only: と except: を記述量の差で使い分けてはいけない。
  • 基本的に only: しか使わない。
  • except: は only: と同列のものではなく、all: の一種である。

将来アクションが追加された時、安全な方に転ぶように使う

1.only: を使うケース

次のようなコードで、
set_something が将来追加されるアクションにも勝手に適用されると困る場合。
(アクションが追加されるごとに適用するかどうかの判断が必要な場合。)

# only: を使った場合
before_action :set_something, only: [:show, :new, :create, :edit, :update, :destroy]
# except: を使った場合
before_action :set_something, except: :index

only: を使った場合は、将来アクションが追加された時、
only: の指定に新しいアクションを追加しないとフィルターが適用されない。

except: を使った場合は、将来どんなアクションが追加されてもフィルターが適用される。

only: を使った場合は、将来アクションが追加された時に
意図せずフィルターが適用されるという事案は発生し得ないが、

except: を使った場合は、将来アクションが追加された時に
意図せずフィルターが適用されてしまうという事案が発生し得るので、

only: を使う。

2.except: を使うケース

例えば次のようなコードで
authorize を将来追加されるアクションにも適用したい場合。

# only: を使った場合
before_action :authorize, only: [:index, :show, :new, :create, :edit, :update, :destroy]
# except: を使った場合
before_action :authorize, except: :login

only: を使った場合は、将来アクションが追加された時
only: の指定に新しいアクションを追加しないとフィルターが適用されない。

except: を使った場合は、将来どんなアクションが追加されてもフィルターが適用される。

only: を使った場合は、将来アクションが追加された時に
フィルターの修正漏れという事案が発生し得るが、

except: を使った場合は将来アクションが追加された時に
フィルターの修正漏れという事案は発生し得ないので、

except: を使う。

3.記述量の差で使い分けてはいけない

という風に考えると、
記述量の差(except: の方が書く量が多いとか少ないとか)で書き分けてはいけない。

それだと将来バグった時に、
たまたま良い方に転ぶかも知れないし、たまたま悪い方に転ぶかも知れない。

と基本的には考えるものの、結果としてほとんどの場合 only: を使う

気持ちの話。

アクションにフィルターを適用したりしなかったりしたい場合は、
ほとんどの場合、将来アクションが追加された場合はその都度判断が必要なはず。

なぜなら、
アクションにフィルターを適用したりしなかったり したくない 場合というのは、
基本的に全てのアクションにフィルターを適用したい場合のはずで、
その場合は将来アクションが追加された時にその都度の判断は不要だけど、
それ以外は、その都度判断が必要なはずだから。

なので、アクションによってフィルターを適用したりしなかったりしたい、
と思った時点で only: を使う。

更に、アクション指定無しのフィルターを便宜的に all: と呼ぶとすると、
フィルターのアクション指定というのは実際には only: しかなくて、
except: というのは only: と同列のものではなくて、all: の一種である。

と考える。

そう考えると、all: 指定時の一部の例外を except: で定義する以外は
全て only: を使えばいいということになる。
(一部の例外がいくつもある場合はそもそも例外じゃない可能性が高いと思う。)

only: を使うメリットと except: を使うデメリット

1.only: を使うメリット

only: を使った場合は、適用されるアクションが全て列挙されているので、
どのアクションに適用されるかは見れば分かる。
ので可読性が上がる。

2.except: を使うデメリット

except: を使った場合は、適用されないアクションだけが列挙されているので、
どのアクションに適用されるかは、見ても分からない、全アクションを把握してないと分からない。
ので可読性が下がる。

3.なのでexcept: に書かれた以外のアクションを把握する必要のある except: は使わない

except: を使う場合は、コードを読み解く上で、
except: に書かれた以外のアクションを把握する必要がない場合に限る。

というか except: に指定されている以外のアクションを把握していないと
理解できないコードというのは根本的に何かが間違っている可能性が高いと思う。

  • 一部の例外じゃなくて、多数の例外で、そもそも例外じゃないとか
  • そもそもフィルターとして実装するのに適していない処理だとか
  • フィルター書きすぎとか(頑張って共通化し過ぎて意味不明になってるパターン)
  • コントローラーの抽象化に失敗してるとか

※ 個人的にはコントローラーの抽象化はしない、
  なぜなら頭が悪くてそんなことできないから、考えるだけ時間の無駄なので。