Rails: メールをActive Recordのコールバックで送信しないこと(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Rails: メールをActive Recordのコールバックで送信しないこと(翻訳)

Railsアプリケーションで何かとやってみたくなることのひとつといえば、メール送信でしょう。

モデルのインスタンスが変更または作成されたときにメールを送信するというのが、よくあるパターンです。

次のようにしないこと

モデルのコールバックにメール送信を仕込む。

class BookReview < ApplicationRecord
  after_create :send_email_to_author

  private

  def send_email_to_author
    AuthorMailer.
      with(author: author).
      review_notification.
      deliver_now
  end
end

次のようにすること

メールをコントローラで送信する。

class BookReviewsController < ApplicationController
  def create
    BookReview.create(comment_params)
    AuthorMailer.
      with(author: author).
      review_notification.
      deliver_now
  end
end

コールバックで送信すべきでない理由

後でコードに触るときに理解しやすくするためであり、後で自分がびっくりしないためです。

上のコード例で考えてみましょう。本にブックレビューを付けるときに、その本の著者に必ずしもメールを送る必要があるとは限りません。1つ目のサンプルコードでは、ブックレビューを1つ作成する副作用としてメールが発射されてしまいます。

場合によってはrails consoleなどで何か操作するときに、ユーザーが著者にメールを送信せずに本のレビューを作成する必要が生じるかもしれません。コールバックをスキップするメソッドを駆使する方法も一応可能ですが、そこから先は泥沼です。

「やることリスト」をコントローラのアクションの中に置いてそこで全部見えるようにしておく方が、明確かつ手続き的です。この場合、ブックレビューの作成の後に行う別の操作としてメール送信を書いておけば、後でコードを見返したときに意図がずっと明確になります。

それだけではありません。無関係な機能をデバッグするために、モデルのコールバックたちをもれなくチェックして回るのは、認知に大きな負荷がかかってつらい作業になります。自分の頭で把握しておかなければならないコンテキストがぐっと増えてしまうからです。

コールバックで送信する理由があるとすれば

ドキュメントではいつも、メール送信をモデルのコールバックで行うことは「Rails Way」であるとみなされて上のようなコード例が付いていたりします。そして、シンプルなケースであれば実際にはこれといった問題は生じません。しかし、やがてアプリケーションが複雑になってくれば、このアプローチのつらみだけが前面に出てくるようになるのです。

「モデルはファットに、コントローラは薄くすることを目指すべき」とよく言われることもあって、私たちは多くの機能をモデル層に盛り込むようになります。これはもちろん一般的にはよいアドバイスではあります。しかしこれはどちらかというと、コールバックを量産する副作用を使いまくってもよいということではなく、アプリケーションの操作を明確にすることでコントローラ層から複雑さを排除しようという話です。

自分の感覚では、モデル変更に伴ってメールを送信する程度であれば、コールバックベースの抽象化が混乱するほど複雑にはならないと思います。大事なのは、コントローラのアクションが呼び出されると、アプリケーションのユーザーに重要なことが2つ発生することを明確に示すことです。

私は、コントローラのメソッドが複雑になってきたときには、それらをコールバックに押し込めるよりも素のRubyの「Service Object」に移す方が好みです。

おたより発掘

関連記事

Rails: :before_validationコールバックの逸脱した用法を改善する(翻訳)

Rails: Active Recordのコールバックを避けて「Domain Event」を使おう(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

夏のTechRachoフェア2019

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ