Quantcast
Channel: hachi8833の記事一覧|TechRacho by BPS株式会社
Viewing all articles
Browse latest Browse all 1759

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

$
0
0

概要

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

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」を使おう(翻訳)


Viewing all articles
Browse latest Browse all 1759

Trending Articles