ActionMailerの_デリバリコールバックでonly/exceptオプションをサポート

rails/rails

ActionMailer の _deliver 系コールバックに only:except: フィルタを正式に扱えるようになり、ActionController と同様のオプション指定が可能になりました。

背景

only:except: が無視されていたことは ActionMailer のコールバック設計上の不整合でした。 *_delivery 系コールバックは before_action 系と同様に条件付きで実行できるはずですが、実際にはオプションが単に捨てられていました。 このため、特定のメール送信メソッドだけでコールバックを走らせたいケースで回避策として if: を使う必要があり、ドキュメント上も利用可能なオプションが曖昧でした。

開発者はコントローラと同様のインターフェースを期待していた点が問題の根源です。 ActionMailer を使用する多くのアプリケーションで、メール送信前後のロジックをメールテンプレートやジョブとは別に管理したい場面が増えており、フィルタが欠如していると意図しないコールバック実行やバグの温床になっていました。 この PR はその矛盾を解消し、一貫した API を提供することを目的としています。

技術的な変更

_insert_callbacks ラッパーを利用して AbstractController と同等の正規化ロジックを導入しました。 actionmailer/lib/action_mailer/callbacks.rbbefore_deliverafter_deliveraround_deliver がそれぞれ

def before_deliver(*filters, &blk)
  _insert_callbacks(filters, blk) do |name, options|
    set_callback(:deliver, :before, name, options)
  end
end

のように変更され、only:except:options に含まれる形で set_callback に渡されます。

ActionMailer::Base の内部で Callbacks のインクルード順序を調整しました。 actionmailer/lib/action_mailer/base.rb では元々 include Callbacks が先にありましたが、

include AbstractController::Callbacks
include AbstractController::Caching

include Callbacks

のように AbstractController::Callbacks の後に Callbacks を追加し、コールバックの定義が正しく上書きされるようにしました。

設定ドキュメントと CHANGELOG にエントリを追加しました。 actionmailer/CHANGELOG.md

* Add support for `config.action_mailer.raise_on_missing_callback_actions` when using `_deliver` callbacks with `only:` and `except:` options.

が追記され、ガイド guides/source/configuring.md でも config.action_mailer.raise_on_missing_callback_actions が説明されています。

テストスイートに新しい期待を組み込み、動作を検証しました。 actionmailer/test/callbacks_test.rb では only:except: の組み合わせでコールバックが正しく呼び出されるかを確認するテストが追加され、CallbackMailer.deliver_callback_log に期待通りのシンボルが記録されることを assert しています。

設計判断

AbstractController の正規化ロジックを再利用することで一貫性を確保しました。 既存の _normalize_callback_options をそのまま呼び出す形にしたため、コールバックオプションの解釈がコントローラとメール送信で完全に同一になります。 これにより、フレームワーク全体でのオプション処理が集中管理され、将来的な拡張やバグ修正が容易になります。

Callbacks のインクルード順序を調整し、名前空間の衝突を回避しました。 include CallbacksAbstractController::Callbacks の後に置くことで、ActionMailer::Base が正しいコールバックメソッドを取得でき、既存の動作を壊さない安全な拡張となっています。

設定項目 config.action_mailer.raise_on_missing_callback_actions をコントローラと同等に導入しました。 これにより、コールバックが存在しない場合に例外を発生させるかどうかをメール側でも制御でき、開発者は期待通りの失敗をテストしやすくなります。 設計上は「Controller と Mailer の API を揃える」方針が貫かれています。

まとめ

今回の変更は、ActionMailer の _deliver コールバックに only:except: フィルタを正式に導入し、AbstractController と同等の正規化ロジックを活用したことで API の一貫性が向上しました。 既存コードへの互換性を保ちつつ、設定オプションも整備されたため、開発者はメール送信フローをより細かく制御できるようになります。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
6230a408

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文・背景・技術的変更・設計判断(任意)・まとめが揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは `language:filepath` 形式で正しく記述されていますが、PRリンクの記法が `[PR #57581](URL)` となっており、仕様の `[#123](URL)` とは形式が異なります。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Rails/ActionMailer の内部構造に詳しいエンジニア向けの内容で、余計な初心者向け説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論・各論・結論の構成が保たれ、段落はトピックセンテンスで始まり 1 段落 1 トピックが守られています。段落長も適切です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供された Diff と完全に一致し、ファイル名・変更内容も正しく反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている用語は PR の記述と一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明は Diff と PR の内容に基づき正確で、因果関係も論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事の主張はすべて PR タイトル・説明・Diff で裏付けられており、根拠のない推測はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR 番号 (#57581) など数値は正しく記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR タイトルの内容を日本語で正確に要約しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事に LTS やリリース日程等、PR に記載されていない外部知識は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PR の記述と整合しています。