自分がエンジニアバイトをしているところでは週1回Rails勉強会をしています。今回はそのやったところのまとめを残しておきます。
参考書:現場で使える Ruby on Rails 5速習実践ガイド
コントローラの役割
コントローラにはいろいろなコードが書きやすいため、たくさんのコードが集中しやすいです。モデルに書くべきビジネスロジックがコントローラに書かれているなんてことはよくあります。コントローラは受け取ったリクエストに対してレスポンスを返すために、何が必要かをモデルとビューに呼びかけて、レスポンスを作成し返すのが役割です。
然るべき場所にコードを移した後、コントローラには以下のものが残ります。
- アクション群の提供(index、show、new、edit等)
- before_actionやafter_actionのようなアクションの事前、事後のフィルタ群
- paramsに関する処理(ストロングパラメータによる送られた値を安全に受け取れるよう加工等)
- URLの生成に関する処理
- モデルに記述したビジネスロジックの呼び出し
- メールなど、モデル以外のロジックの扱い
- ビューテンプレートのハンドリングやレスポンスそのものの動的作成、リダイレクト先の管理
上記のようなもので似ている部分は共通化をするといいでしょう。ただし共通化する前にMVCの役割にそった所にコードを書いておくのが前提となります。
共通機能をモジュールで複数のコントローラと共有する
共通化したい機能をモジュールにしてそれぞれのコントローラでincludeして使用する。ただポイントとして本当に似ているアクションだけを共通化するようにする。実際の処理の流れが違うものをアクション名が同じなだけで共通化しようとすると、アクション内で条件分岐が行われるなどして、余計に複雑性が上がってしまう。
アクションの中身がほぼ同じといってもコントローラ毎で若干の違いは出てきます。(同じならコントローラを分ける必要がないですから)モジュール内の実装は同じでいいですが、若干の差異を吸収する場所としてコントローラにメソッドとして実装させるのが手としてあります。
共通機能を基底クラス(親クラスにもたせる)を作り、持たせる
アクションの追加をするために継承をするのは基本避けるべきでしょう。以下のようなことがあるからです。
- 基底クラスは簡単に外したり、分割できない。結果、一部のコントローラに不要なアクションが存在したり、アクションメソッドのオーバーライド(子クラスが親クラスのメソッドを上書きすること)が起きたりするから。
- モジュールが必要な時にだけ使用する「追加的存在」であるのに対して、継承における基底クラスとは子クラスがそもそも備えているべき「基本的性質」を表す存在です。継承している全てのクラスが、追加するアクションの性質を持ち合わせているかを網羅するのは難しいからです。
結果としてコントローラの継承では、privateメソッドの実装や、フィルタ定義などのアクション以外の処理を共通化することを行うのがいいでしょう。
1. アクションを実装している通常のコントローラクラス
2. アクションは実装していない、共通処理をかいた基底コントローラクラス
ApplicationControllerに共通処理を持たせる
ApplicationControllerに共通処理を持たせることですべてのコントローラで使用することができます。
- ログインしているかどうかの判定
- 権限チェックをし、エラーをだす
汎用的に使えそうな処理をprivateメソッドに書いておき呼ばれない限り誤作動に注意しておくといいでしょう。