升级Ruby 3.1后调用test.save!报ArgumentError参数不匹配问题
Ruby 3.1升级后
save!触发ArgumentError的解决方法 问题描述
升级至Ruby 3.1后,执行种子数据方法seed_test_program中的test.save!时,出现错误:
ArgumentError: wrong number of arguments (given 1, expected 0)
相关种子方法核心代码:
def seed_test_program test = TestProgram.find_or_initialize_by( name: "Program", code: :program ) test.metadata["status_types"] = [ "enrolled", "excluded", "rejected", "not_enrolled" ] test.metadata["status_reasons"] = { "excluded" => ["reason 1", "reason 2", "reason 3"], 'rejected' => ["reason 1", "reason 2", "reason 3"], "not_enrolled" => ["reason 1", "reason 2", "other"] } test.save! # 报错触发位置 Test.program.reload end
堆栈跟踪指向seed_test_program方法,但核心问题并非种子代码本身,而是TestProgram模型的逻辑与Ruby 3.1的参数规则不兼容。
核心原因
Ruby 3.0+对关键字参数与哈希的隐式转换做了严格限制,此前版本允许将哈希当作关键字参数隐式传递,但3.1版本中该行为被禁止。如果TestProgram模型存在以下情况,就会触发该错误:
- 重写了
save!/save方法,但未定义关键字参数接收逻辑; - 模型回调方法(如
before_save、after_save等)的参数定义与Active Record的调用方式不匹配; metadata属性的自定义存取器(metadata=)存在参数处理问题。
解决步骤
1. 检查TestProgram模型的save!/save重写
如果模型中重写了save!,需确保方法接受关键字参数并传递给父类:
# 错误写法(Ruby 3.1会报错) class TestProgram < ApplicationRecord def save! # 自定义逻辑 super end end # 正确写法 class TestProgram < ApplicationRecord def save!(**options) # 自定义逻辑 super(**options) end end
重写save方法时遵循相同规则:def save(**options); super(**options); end
2. 排查模型回调方法
检查所有与保存相关的回调,确保方法参数定义正确。例如,回调方法默认无需额外参数,若错误定义了多余参数会导致报错:
# 错误示例:回调方法多余参数 before_save :sync_metadata def sync_metadata(record) # 多余参数触发报错 # 逻辑 end # 正确写法 before_save :sync_metadata def sync_metadata # 逻辑 end
3. 检查metadata属性的自定义处理
如果metadata是JSON/JSONB字段且自定义了存取器,需确保metadata=方法能正确处理哈希赋值:
# 错误写法(若存在) def metadata=(value) # 未正确处理哈希参数 write_attribute(:metadata, value.to_json) end # 正确写法 def metadata=(value) write_attribute(:metadata, value.is_a?(Hash) ? value : JSON.parse(value)) end
验证方法
修改模型代码后,重新执行种子任务:
rails db:seed
若错误消失,则说明问题已解决。
内容的提问来源于stack exchange,提问作者TryingNewThings
相关产品推荐
相关产品推荐

