suusan2号の戯れ

SIerでインフラSE⇛WEB系でエンジニアのおっさん

Railsでももっとカジュアルにapp/models配下にクラス作っていいんじゃないかなーと思っているんだけどどうなんでしょうか

Railsのプロジェクトやってると、app/models には ActiveRecord だけ、それ以外のオブジェクトは app/services とか app/forms層みたいなところに定義しないといけないと思っている人がそれなりに多い気がする。

個人的には app/models 配下に責務を分けたActiveRecordでないクラスを作っていくのはむしろ積極的にやるべきだと思っている。むしろそうしないとXX層みたいなものを導入したとしても、本来モデルの振る舞いとして表現されるべきものが手続き的に書かれてしまったり、新しく導入したXX層の処理がファットになっていってしまったりするのではなかろうか。(ActiveRecord のクラスと、そうじゃないプレーンなRubyクラスが app/models に交じるのが気持ち悪いという意見はまあ理解できるけど)

たとえば

たとえば以下のようなクラスがあったとする。

class User < ApplicationRecord
  def nanka_fukuzatu_na_shori
    if user.hoge?
       private_na_method_a
       private_na_method_c
    else
       private_na_method_b
    end
  end

  private

  def private_na_method_a
     # なんかの処理
  end


  def private_na_method_b
     # なんかの処理
  end


  def private_na_method_c
     # なんかの処理
  end
end

見るとnanka_fukuzatu_na_shoriprivate_na_method_a~c は明らかに関連をもつひとまとまりの処理なので、こいつらを実行する実態はUserクラスではないところにあっても良さそうな気がする。

これを User::NankaFukuzatsuNaShoriHandler を作って、そちらに責務を分けてみる

# app/models/user/nanka_fukuzatu_na_shori.rb
class User:: NankaFukuzatsuNaShoriHandler
  attr_reader :user

  def initialize(user:)
    @user = user
  end

  def perform
    if user.hoge?
       private_na_method_a
       private_na_method_c
    else
       private_na_method_b
    end
  end

  private

  def private_na_method_a
     # なんかの処理
  end


  def private_na_method_b
     # なんかの処理
  end


  def private_na_method_c
     # なんかの処理
  end
end

( nanka_fukuzatu_na_shori とかいう適当な名前で書き始めてしまったので User::NanakaFukuzatuNaShoriHandler#perform みたいにしちゃったけど、HandlerPerform みたいな抽象的な名前は避けたほうが良さそう)

Userクラスはこんな感じになる。

class User < ApplicationRecord
  def nanka_fukuzatu_na_shori
    nanka_fukuzatu_na_shori_handler.perform
  end

  private

  def nanka_fukuzatu_na_shori_handler
    @nanka_fukuzatsu_na_shori_handler ||= User::NankaFukuzatsuNaShoriHandler.new(user: user)
  end
end

基本的にはこんな感じで責務を分割していって、あるモデルの振る舞いとして定義するのが微妙なものだけそれこそXXX層みたいなの作ってやるのがいいんじゃないかと最近は思うんだけど、各社どうなっているんだろう。

  • Rails Wayから外れるので止めたほうがよい
  • Concern使えば?

みたいな意見はありそうかなと思っています。

参考文献

rubyblog.pro

qiita.com