Ruby3.2.x+Rails6.1.7.x下ActionMailer参数错误求助
Ruby 3.2.x 搭配 Rails 6.1.7.x 邮件发送 ArgumentError 问题解决
问题背景
升级到 Ruby 3.2.2 + Rails 6.1.7.8 后,原有的邮件发送功能触发 ArgumentError,此前在 Ruby 2.7.8 + Rails 6.1.7.7 环境下运行正常。RSpec 测试全部失败,控制台调用也无法成功。
错误信息
ArgumentError: wrong number of arguments (given 1, expected 0; required keywords: email, message) from /Users/<username>/Projects/<application_name>/app/mailers/alert_mailer.rb:4:in `pmp_throttling_event'
邮件类代码
class AlertMailer < ApplicationMailer def pmp_throttling_event(email:, message:) message = message.with_indifferent_access pmp_name = message[:pmp_name] email_body = translate_for_erb(message[:email_body]) email_subject = translate_for_erb(message[:email_subject]) body = ERB.new(email_body).result(binding) subject = ERB.new(email_subject).result(binding) if body.blank? || subject.blank? logger.error 'email body and subject must be provided' return end mail(to: email, subject: subject) do |format| format.html { render plain: body } format.text { render plain: ActionController::Base.helpers.strip_tags(body) } end end end
尝试过的调用方式
- 直接传递关键字参数
AlertMailer.pmp_throttling_event(email: 'test@example.com', message: { email_body: 'test', email_subject: 'test' }).deliver_now - 使用哈希展开
args = {email: 'mknittel@bamboohealth.com', message: { email_body: 'test', email_subject: 'test' }} AlertMailer.pmp_throttling_event(**args).deliver_now
两种方式均返回上述错误。
已尝试的操作
- 降级 Rails 到 6.1.7.7,问题依旧
- 升级到 Rails 7.x,引入更多兼容性问题
- 尝试 Ruby 3.2.5 + Rails 6.1.7.8,问题未解决
问题原因
Ruby 3.0+ 彻底分离了位置参数与关键字参数,而 Rails 6.1.x 的邮件类方法转发逻辑未适配 Ruby 3.2 的参数处理规则:调用 AlertMailer.pmp_throttling_event 时,Rails 会将传入的关键字参数打包成一个哈希传递给实例方法,导致实例方法收到 1 个哈希参数,而非预期的两个独立关键字参数。
解决办法
方法一:修改邮件方法参数定义(推荐)
将实例方法改为接收关键字参数展开形式,兼容 Ruby 3.x 的参数传递逻辑:
class AlertMailer < ApplicationMailer def pmp_throttling_event(**kwargs) # 强制获取必填参数,确保参数校验 email = kwargs.fetch(:email) message = kwargs.fetch(:message).with_indifferent_access pmp_name = message[:pmp_name] email_body = translate_for_erb(message[:email_body]) email_subject = translate_for_erb(message[:email_subject]) body = ERB.new(email_body).result(binding) subject = ERB.new(email_subject).result(binding) if body.blank? || subject.blank? logger.error 'email body and subject must be provided' return end mail(to: email, subject: subject) do |format| format.html { render plain: body } format.text { render plain: ActionController::Base.helpers.strip_tags(body) } end end end
方法二:直接调用实例方法
绕过 Rails 的类方法参数转发逻辑,直接初始化邮件类实例并调用方法:
AlertMailer.new.pmp_throttling_event(email: 'test@example.com', message: { email_body: 'test', email_subject: 'test' }).deliver_now
方法三:启用 Ruby 关键字参数兼容模式(临时方案)
在启动应用时添加 Ruby 兼容参数,强制转换关键字参数:
RUBYOPT="--enable-keyword-argument-conversion" rails s
此方法仅作为临时测试,不推荐长期使用,可能影响其他代码的参数处理逻辑。
内容的提问来源于stack exchange,提问作者mikek765
相关产品推荐
相关产品推荐

