Rails 8.1で`ActionMailer::Base.mail`が`ActionNotFound`を引き起こすリグレッションを修正

rails/rails

Rails 8.1でActionMailer::Base.mailをクラスレベルで直接呼び出すとAbstractController::ActionNotFoundが発生するリグレッションが修正されました。クラスレベルにmailメソッドとaction_methodsの上書きを追加することで、Rails 8.0の動作が復元されます。

背景

Rails 8.1ではActionMailer::Base.mailが「アクション」として認識されなくなり、直接呼び出した際にAbstractController::ActionNotFoundが発生するリグレッションが混入しました。このバグは#56449として報告されています。

問題を再現するコードは以下のとおりです。

ActionMailer::Base.mail(
  from:    'test@test.com',
  to:      'test@test.com',
  subject: 'Test',
  body:    'test'
).deliver

これを実行すると、AbstractController::Base#processmailをアクションとして発見できず、以下のエラーが発生していました。

The action 'mail' could not be found for ActionMailer::Base (AbstractController::ActionNotFound)

サブクラスを定義してメーラーを作成する通常のユースケースでは問題が起きませんが、ActionMailer::Baseを直接利用する使い方はシンプルなスクリプトや既存コードで広く使われており、影響範囲は軽視できません。

技術的な変更

actionmailer/lib/action_mailer/base.rbのクラスメソッドとしてmailaction_methodsの2つが追加されました。

変更後:

def mail(...)
  MessageDelivery.new(self, :mail, ...)
end

def action_methods
  methods = super
  methods.add("mail") if self == ActionMailer::Base
  methods
end

クラスレベルのmailメソッドは、selfActionMailer::Baseクラス自身)と:mailシンボルを引数としてMessageDelivery.newを呼び出し、受け取ったキーワード引数をそのまま転送します。これにより、サブクラスを介さずにMessageDeliveryオブジェクトを生成できます。

action_methodsの上書きでは、self == ActionMailer::Baseの場合に限り"mail"をセットに追加します。サブクラスではsuperの結果をそのまま返すため、既存のサブクラスの動作に影響を与えません。この条件付き追加こそが、AbstractController::Base#processmailをアクションとして発見できるようにする核心的な変更です。

テスト面では、actionmailer/test/base_test.rbに2つのテストが追加されています。1つはdeliver_nowまで実行してデリバリー件数とsubjectを検証するもの、もう1つはMessageDeliveryオブジェクトの内容を検証するものです。また、既存のテストでassert_not_respond_to BaseMailer, :mailだった行がassert_respond_to BaseMailer, :mailに変更されており、サブクラスでもmailがパブリックに呼び出せることが保証されています。

設計判断

ActionMailer::Baseクラスにのみ"mail"を追加する方式が採用されました。

action_methodsの上書きでself == ActionMailer::Baseという条件が設けられているのは、サブクラスにまでmailをアクションとして公開しないためです。サブクラスではユーザー定義のアクションメソッドだけがアクションとして機能すべきであり、基底クラスのディスパッチ用メソッドが混入するとルーティングや意図しないアクション呼び出しが生じる恐れがあります。最小限の条件分岐で対象を限定することで、既存のサブクラス利用への副作用を排除しています。

クラスレベルのmailメソッドがMessageDelivery.new(self, :mail, ...)を返す実装も注目に値します。サブクラスのアクションと同じMessageDeliveryインターフェースを返すことで、deliver_nowdeliver_laterなどの呼び出しがそのまま機能します。

まとめ

本PRはActionMailer::Baseのクラスメソッド2つを追加するだけの小さな変更で、Rails 8.0からの後退を解消しています。action_methodsを条件付きで拡張することで、基底クラスの直接利用と既存サブクラスの振る舞いを同時に保証するアプローチは、Abstract Controllerのアクション検出機構への深い理解に基づいた判断といえます。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
f97ee89c

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)、背景・技術詳細・設計判断(各論)、まとめ(結論)という「総論→各論→結論」の構成が非常に明確です。必須要素はすべて満たしており、任意要素である「設計判断」も含まれているため、内容の理解が深まります。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```ruby:actionmailer/lib/action_mailer/base.rb)およびGitHubのPR・Issueへのリンク記法([#56449](...))が、ガイドライン通りに正しく使用されています。

対象読者への適合性 ✓ PASS

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

「AbstractController」「action_methods」といったRailsの内部実装に関する用語を前提知識として使用しており、専門のエンジニアという対象読者に完全に適合しています。

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

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

各セクションが総論・各論で構成され、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が徹底されています。段落の長さも適切で、非常に読みやすいです。

Diff内容との照合 ✓ PASS

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

記事で引用されている`actionmailer/lib/action_mailer/base.rb`のコードは、提供されたDiffの内容と完全に一致しており、正確に引用されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`AbstractController::ActionNotFound`, `MessageDelivery`, `action_methods`といった技術用語が、文脈に沿って正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

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

「`action_methods`を条件付きで拡張することで、`AbstractController`が`mail`をアクションとして認識できるようになる」という説明は、PRの変更内容と技術的背景を正確に捉えています。

事実の突合 ✓ PASS

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

記事で述べられている背景、技術的な変更点、設計判断のすべてが、提供されたPRのDescriptionやDiffの内容によって裏付けられており、ハルシネーション(捏造)は見られません。

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

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

PR番号(#56450)、Issue番号(#56449)、関連するRailsのバージョン番号(8.1, 8.0)など、すべての数値・固有名詞が正確に記載されています。

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

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

記事のタイトル「Rails 8.1で`ActionMailer::Base.mail`が`ActionNotFound`を引き起こすリグレッションを修正」は、PRの主題を的確に反映しており、内容との整合性も取れています。

外部知識の正確性 ✓ PASS

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

記事の内容はすべて提供されたPR情報に基づいており、LTSやEOLといったPRに記載のない外部知識の持ち込みはありません。

時間表現の正確性 ✓ PASS

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

「Rails 8.1で...リグレッションが混入しました」「Rails 8.0の動作が復元されます」など、事象の発生時期や前後関係に関する時間表現は、PRの情報と一致しており正確です。