4
0

More than 1 year has passed since last update.

ActiveRecordのコールバックをInteractor層を使ってリファクタリングする

Posted at

Interactor とは

Interactor はアプリケーションのそれ以上分割できない責務の動きを実現する
アプリケーションのビジネスロジックをカプセル化するために使われるオブジェクトです

ActiveRecordのコールバック

Railsガイドでは下記のように説明されています

コールバックとは、オブジェクトのライフサイクル期間における特定の瞬間に呼び出されるメソッドのことです。 コールバックを利用することで、Active Recordオブジェクトが作成/保存/更新/削除/検証/データベースからの読み込み、などのイベント発生時に常に実行されるコードを書くことができます。

Active Record コールバック - Railsガイド

便利な反面副作用が大きく controller でどんな処理が行われるか意識・制御ができない点が問題です
またモデルが太る原因にもなります
実際コールバックを多用するとコールバックを起点にまたコールバックが呼ばれて...と考えたくもない連鎖反応が起こり思いもよらないバグを生んだりします
すべてのコールバックはやめておいたほうが良い分けてはありませんが多用することは避けたほうが良いでしょう

リファクタリングの例

例えば、ユーザを作成したらコールバックを使ってメールを送るメソッドが書かれていたとする
このような実装の場合、Admin画面から User を作成する場合はMailを送りたくない等を実現することが難しくなる
(if文を使って制御することはできるが可読性は下がる)

コールバックが書かれたUserモデルの例

class User < ApplicationRecord
  after_create :create_notification

  private

  def create_notification
    UserCreatedMailer
      .with(user: self)
      .create
      .deliver_later!
  end
end

そこで使いたいのがInteractor層です
今回ではUserを作成する責務だけを負うCreateUserを作ります
これによってMailを送りたくない場合などが発生した場合には新たなInteractor層を作成することで容易に対応することができます
これらをモデルに記載する必要がないのでモデルが太ることもありません

Interactorを使ったUser作成

class CreateUser
  attr_reader :args

  def initialize(**args)
    @args = args
  end
  
  def call
    user = User.new(**args)
    result = user.save
    create_notification(user) if result
    result
  end

  private

  def create_notification(user)
    UserCreatedMailer
      .with(user: user)
      .create
      .deliver_later!
  end
end
4
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
4
0