LoginSignup
0
0

More than 1 year has passed since last update.

Railsのクラスメソッドについて考える

Last updated at Posted at 2022-09-06

本題

  • Railsで書いてるとクラスメソッドでいろいろやりがちにならない?と思ったので解決策を考える。

ファーストクラスコレクション 

良いコード、悪いコードで学ぶ設計入門という本を最近読んで、ファーストクラスコレクションという物があることを知りました。
今までrailsのみで開発をしてきたので、こんな書き方があるんだなーと思いました。
それと同時に Railsのクラスメソッドでいろいろやりすぎ?? という疑問が浮かびました。

原因

ActiveRecord::Relation がクラスメソッドを実行できるのでそうなりがちなのでは?と思いました。
User modelが存在すると仮定して、APIでユーザーの名前、年齢を返すAPIを想定します。

# app/models/user.rb
class User < ActiveRecord::Base
  scope: otona, -> { where('age >= 18') }

  def self.name_and_age
    all.each_with_object([]) { |user, result|
      result << { name: user.name, age: user.age }
    }
  end
end

# app/controllers/api/users_controller.rb
class UsersController < ApplicationController
  def index
    render json: { users: User.otona.name_and_age }
  end
end

ここで違和感が発生します。
User#name_and_age がUserクラスに存在する違和感、つまり、これってUsersクラスで良くない?ってことです。
Userクラスはあくまでそのクラスのインスタンスである1ユーザーのことに集中すべきで、そうすることで責務も適切に分けることができそうな気がします。
以下のように変更してみます。

# app/models/users.rb
class Users
  def initialize(users)
    @users = users
  end
  
  def name_and_age
    @users.each_with_object([]) { |user, result|
      result << { name: user.name, age: user.age }
    }
  end
end

# app/controllers/api/users_controller.rb
class Userscontroller < ApplicationController
  def index
    render json: { users: Users.new(User.otona).name_and_age }
  end
end

パッと見た感じ良い感じに責務を分けれたように思えます。
ただ、こんな単純な場合ではなく、Usersクラスの中で @users.includes(....) などすることは考えられるため、ActiveRecord::Relationをnewする時に渡す、という使い方になりそうな気がします。そうなると、ただクラスメソッドを別のクラスに移しただけでは?というような気もしてきますよね。

最後に

Railsで開発しているとオブジェクト指向を意識する機会が少ないのかもしれないと思ってきました。有識者の皆さんの意見をお待ちしてます!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0