You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:22:16