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 は場違いだったということです。