Railsのbefore_actionについて思うところ
どうも nasa です。
今日、Rails で開発しててつらみがあったのでつらつらと書いていきます。
Rails を例にとって話すので、Rails 知らん!って人はごめん。 なるべく分かりやすく書いてみるけど人に分かりやすく伝えるということが苦手なもので、、、
まずこんなコードがあったとする
簡単に言うと、DB から id = 1 のユーザーを持ってきて、@user に入れてね〜っていうやつ
class やら def new やらはあまり気にしなくて良い、あるリクエストが来たらこの new メソッドが呼ばれる Rails マジックがあるのだよ
class HogeController < ApplicationController def new @user = User.find(1) end end
じゃあユーザー情報の更新したいわってなるとする
class HogeController < ApplicationController def new @user = User.find(1) end def edit @user = User.find(1) @user.update # 更新処理 end end
ふむ。User.find(1)が2つありますね このコードは Rails のお作法に従えばこうなる before_aciton があるとこの場合 set_user が最初に呼ばれる
class HogeController < ApplicationController before_action :set_user, only: %i(new edit) def new end def edit @user.update # 更新処理 end def set_user @user = User.find(1) end end
ふむふむ。new の edit がスッキリしたぞ!
だが、考えることがある。 スッキリはしたがこれで良いのか? (まあ、今んところ問題ない, コード量が少ないからね)
class HogeController < ApplicationController before_action :set_user, only: %i(new edit) before_action :set_searched_user, only: %i(new) before_action :set_users, only: %i(edit) def new end def edit @user.update # 更新処理 end def set_user @user = User.find(1) end def set_searched_user @users = 検索で絞り込んだuser達 end def set_users @users = user全件 end end
さあ。ちょっと面倒になってきたかな? コードが少ないからそんなことないかな? new には検索で何かしらの条件で絞り込んだ users がある、edit にはユーザー全件がある
じゃあ、これで最後
class HogeController < ApplicationController before_action :set_user, only: %i(new edit) before_action :set_searched_users, only: %i(new) before_action :set_users, only: %i(edit) # 以下全部何かしらの情報をuserを元に取得してインスタンス変数に格納するものとする before_action :set_books only: %i(new edit) before_action :build_book, only: %i(new edit) before_action :get_tweet,only: %i(edit) before_action :set_reports, only: %i(new) def new end def edit @user.update # 更新処理 end # 以下略
例をつらつら上げても読んでいる人は面白くないということに今気づいたので最後の例です。
before_action がいっぱいあったとします。 もう、new には何がセットされていて、edit には何があるかわかりませんね。
そう。今日はこれにぶち当たったのです。 もっと偉大なコードでした。before_action が28こあり、25 個の Controller で include されていました。見通しが悪すぎます、、、
じゃあ、どうするのかって話ですが、action に処理を書きましょう!それで見通しが良くなるはずです。ただ、なるべく共通部分は抜き出して
class HogeController < ApplicationController def new @user = set_user @users = set_searched_users @books = set_books @book = build_book @report = set_seport end def edit @user = set_user @users = set_users @books = set_books @book = build_book @tweet = get_tweet @user.update # 更新処理 end # 以下メソッド軍がある end
set_hoge 系統のメソッド名を変えずにそのまま書きましたが、適切な名前がついている想定です。 ユーザー検索や tweet 取得などのメソッドも定義されている想定です
@user = や @book = の処理が2回記述されていてもっと DRY になるのではみたいな意見もあるかと思いますがこっちのほうが見通しが良いかと思います。
まとめ
まあ、何が言いたかったかというと、set_hoge のような before_action は多様せずに普通に action に書くことで action を見ればこれが何をしているのかがひと目で分かっていいよね〜ということです。 全く before_action を書くなと言うことではなく、あいつにはあいつの輝く場所がありますが、set_hoge は場違いだったということです。