ここでいう標準な CRUD とは下記のアクション群 (scaffold で生成されるアクション)
- index
- show
- new
- edit
- create
- update
- destroy
標準のCRUDなアクション以外生やし始めると、徐々にコントローラがカオス化する気がしませんか?
生やしたい派の意見としては共通ロジックをコントローラで使いまわせる、ルーティングからコードの配置がわかりやすい (?)、などなど
でも生やした結果、最終的にコントローラがカオス化してるケースを何件も見てきました。。。 (アクションが数十個、全体で数百行に成長したコントローラ。。。
個人的には、よくある検索用の search や完了ページ的な finish (complite) みたいなアクションでさえ別コントローラに切り出すでよくないかと思ってしまう。それくらい強いルールがあったほうが秩序が保たれるんじゃないかと。。。
実際のイメージですが、Tweet (つぶやき) 用のコントローラを用意したい場合で考えてみます。
class TweetsController # GET /tweets def index # 一覧ページ end # GET /tweets/new def new # 投稿ページ end # POST /tweets def create # 投稿処理 end # GET /tweets/search def search # 検索用ページ end # GET /tweets/finish def finish # 投稿完了用ページ end end
このコントローラを
class TweetsController # GET /tweets def index # 一覧ページ end # GET /tweets/new def new # 投稿ページ end # POST /tweets def create # 投稿処理 end end class Tweet::SearchesController # GET /tweet/search def show # show なのは単一ルーティングで表現を想定しているため end end class Tweet::FinishesController # GET /tweet/finish or /tweets/:id/finish def show # show なのは単一ルーティングで表現を想定しているため end end # routes.rb Rails.application.routes.draw do resources :tweets, only: [:index, :new, :create] do scope module: :tweet do resource :finish, only: :show end end namespace :tweet do resource :search, only: :show end end
このような形で実装する。 上記 routes.rb の記述で作成されるルーティングは下記。
Helper | Path | Controller#Action |
---|---|---|
tweet_finish_path | GET /tweets/:tweet_id/finish(.:format) | tweet/finishes#show |
tweets_path | GET /tweets(.:format) | tweets#index |
POST /tweets(.:format) | tweets#create | |
new_tweet_path | GET /tweets/new(.:format) | tweets#new |
tweet_search_path | GET /tweet/search(.:format) | tweet/searches#show |
こういう感じで routes.rb で resource(s) ベースでコントローラを作ることをルール化すれば、標準 CRUD なアクションのみ対応でき、実装に統一感もでます。標準 CRUD なアクションのみになるので、7 つ以上のルーティングをひとつのコントローラで制御することがなくなり、シンプルになると思います。
また、コントローラを分割することで、分割されたコントローラ間で利用したい共通ロジックが出てくる場合もあると思います。そうなると、外 (例えば Concern など) に切り出す必要がでるため、コントローラのコード量が減りさらに薄くなります。
外に切り出しやコントローラの分割でファイル数自体は増えるでしょうが、ルーティングの生成されるパスからファイルも推測しやすいですし、大きな問題ではないと思います。
正直コントローラは薄ければ薄いほど嬉しいと思っていて、アクションが数十個、全体で数百行あるようなコントローラは読んでられません。ただでさえ Fat 化させやすいレイヤーだと思うので、個人的には厳しいルールで縛ってなるべく全体の見通しがよくしたいなと思っています。
Rubocop でそういう cop は現時点で存在しないようなので、時間があるときにカスタム cop を作れたらいいなと思っています。
以上です。