Callbackメソッドの「only」「except」の使い分け(Rails)

f:id:ryoutaku_jo:20190912000324p:plain

【結論】

・Controllerのコールバックメソッドは、onlyexceptで実行するアクションを指定できるが、適切に使い分けないと、バグ発生の要因となり得る

・基本的にonlyを使用する。指定するアクションが増えて、追加するアクションが無くなったらexceptに置き換える。

・権限の制御など、アクションの実行に制限を設けるコールバックであれば、始めからexceptを利用する。

【目次】

【本題】

Callbackメソッドのオプションの使い分け

before_actionafter_actionといったControllerのCallbackメソッドは、オプションでコールバックを実行させるアクションを指定することができます。

onlyでは、指定したアクションだけ、コールバックが実行されます。

exceptでは、指定したアクション以外で、コールバックが実行されます。

class PostsController < ApplicationController
  before_action :authenticate_user!, :except=>[:show]
  before_action :set_post, only: [:show, :edit]

  def show
    @post_comments = PostComment.where(post_id: params[:id])
  end

  def edit
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end
end

これにより、共通の処理を一つの記述にまとめることが出来て、コードの見通しが良くなります。

暗黙的に実行されていることによる弊害

しかしコールバックの処理は、アクション内では明示されていない為、存在を見落としてしまう可能性もあります。

そうなると、アクションを指定し忘れてしまい、それによって意図せぬ挙動が発生してしまうリスクがあります。

例えば、本来は管理者しかアクセスできないページ(アクション)に、一般のユーザーもアクセスできてしまうという事象です。

なので、アクションの指定方法も、それらのリスクを最小限に留めるように設定を行う必要があります。

基本的にonlyを使用する

exceptだと明示的に指定したアクション以外にコールバックが適用されます。

なので、アクションを追加した際にコールバックを見落としてしまうと、本来適用したくなかったコールバックが適用されてしまうことになってしまいます。

onlyを使用すれば、実行するアクションを明示的に指定できるので、意図せぬコールバックが適用される事態は防げます。

しかし、適用するアクションが増えるほど記述量が多くなり、見通しが悪くなることで、どのアクションにコールバックが適用されているのか見辛くなります。

そこで、exceptで書いた方が記述量が減るのであれば、exceptに置き換えましょう。

但し、今後もアクションを追加する予定があるのであれば、exceptに置き換えることで先ほどの問題が発生する可能性もあるので、アクションの追加がひと段落してからの方が良いでしょう。

制限を設けるコールバックはexceptを使用する

基本的にはonlyを使用しますが、exceptを使用した方が良いと思われる場合もあります。

それはコールバックによって、アクションの実行に制限を設ける場合です。

例えば「管理者のみアクセスできるようにしたい」といった権限の制御などです(そもそもコールバックで処理すべきでは無いかもしれないですが・・・)

これをonlyで設定してしまうと、もしコールバックの設定を見逃した場合、一般のユーザーでも管理者専用のアクションが実行できてしまいます。

exceptを使用すれば、追加したアクションに直ぐコールバックが適用されるので、こういった事態を防ぐことが可能です。

参考情報

Action Controller の概要 - Rails ガイド

AbstractController::Callbacks::ClassMethods

《今日の学習進捗(3年以内に10000時間に向けて)》

CSVインポート機能のリファクタリングの一環で、バルクインサート部分を試しに取っ払ってみたが、処理時間が10倍くらい増えてしまった。
コードの見通しは若干良くなったものの、実用性に乏しいので、バルクインサートで開発を続ける。

なお、ページのアクセス制御が意図した通りに機能していないバグが見つかった為、修正を行っている。
該当ページは複数の要素で制御されており、ロジックが複雑になっている。
このあたりの仕様は、ビジネスサイドからの依頼で急遽追加されたり、リリースに向けて急ごしらえで開発を進めたりで、十分に全体の挙動を考慮できていなかった。

また、設計についても、ビュー側で表示の制御を行っていたりと、かなり大雑把な作りになっている。
バグ修正と合わせて、ロジックをビューからコントローラーに寄せたり、全パターンのテストを追加して、再発防止に努めたい。

学習開始からの期間 :278日
今日までの合計時間:2601h
一日あたりの平均学習時間:9.4h
今日までに到達すべき目標時間:2539h
目標との解離:62h
「10,000時間」まで、

残り・・・「7399時間!」