升级Ruby至3.2.2后mail 2.8.1的deliver_now方法传参报错
Ruby 3.2.2 + Rails 6.1.7 + Mail 2.8.1:deliver_now调用时的关键字参数错误
问题场景
基于Rails 6.1.7的项目,将Ruby升级至3.2.2后,使用mail 2.8.1版本时,执行邮件发送代码:
TestMailer.test_mail(one: foo, two: bar).deliver_now
抛出如下错误:
wrong number of arguments (given 1, expected 0; required keywords: one, two) (ArgumentError)
对应的邮件方法定义为:
def test_mail(one:, two:) attach_files([one.last.pdf_path.to_s]) if two send_mail(one: one) end
将mail锁定为2.7.1版本,同时Ruby仅升级至3.0.4时,代码可正常运行。
原因分析
Ruby 3.0及以上版本对关键字参数的处理逻辑做了调整,而mail 2.8.1在与Rails 6.1.7、Ruby 3.2.2配合时,内部处理deliver_now流程中存在参数传递的兼容性问题——gem可能错误地将调用时传入的关键字参数封装成了单个哈希位置参数,导致邮件方法接收参数时触发校验错误。
解决方案
- 降级mail gem:将Gemfile中的mail版本锁定为2.7.1,同时可暂时维持Ruby版本在3.0.4,直接恢复兼容性。
- 升级Rails补丁版本:将Rails升级至6.1.x分支的最新补丁版(如6.1.7.6及以上),Rails官方后续补丁修复了部分与Ruby 3.2及mail gem的参数兼容问题。
- 修改邮件方法参数兼容:如果需要保留Ruby 3.2.2和mail 2.8.1,可修改邮件方法的参数接收逻辑,兼容两种参数传递形式:
def test_mail(*args, one:, two:) # 兼容可能被封装成哈希的参数 if args.present? one = args.first[:one] || one two = args.first[:two] || two end attach_files([one.last.pdf_path.to_s]) if two send_mail(one: one) end
注意:此方案需要全面测试,避免影响其他邮件调用场景。
内容的提问来源于stack exchange,提问作者Theoran
相关产品推荐
相关产品推荐

