Rails中如何将select_tag的order_source参数传入模型验证器?
如何将order_source参数传入CashInOrder模型的验证器?
问题背景
你遇到的NoMethodError核心原因很明确:你的CashInOrder模型没有定义order_source属性,虽然表单提交时参数传过来了,控制器也允许了该参数,但因为模型没有对应的属性(不管是数据库字段还是虚拟属性),实例自然访问不到这个值。
解决办法
这里有两种可行的方案,你可以根据需求选择:
方案1:给模型添加数据库字段(推荐,适合需要持久化支付来源的场景)
如果你需要记录用户选择的支付卡ID,后续可能需要查询或关联,直接给cash_in_orders表加字段是最稳妥的:
- 生成迁移文件:
rails generate migration AddOrderSourceToCashInOrders order_source:string - 运行迁移:
rails db:migrate
这样处理后,cash_in_order_params里的order_source会被自动赋值给模型实例的属性,验证器里self.order_source就能正常调用了。
方案2:使用虚拟属性(适合不需要持久化该字段的场景)
如果不需要把order_source存到数据库,只需要在验证时临时使用,可以给模型添加虚拟属性:
在CashInOrder模型顶部添加:
class CashInOrder < ApplicationRecord attr_accessor :order_source # 添加这行 validate :is_cashed_in # ... 其他代码 end
attr_accessor会给模型实例创建对应的getter和setter方法,控制器的参数会自动赋值给这个虚拟属性,验证器里就能正常访问self.order_source了。
额外需要修正的小问题
除了上面的核心问题,你的验证器里还有个小bug:
Stripe::Charge.create(:amount => (amount.to_f*100).to_i, ...)
这里的amount变量没有定义,应该改成self.order_sum,也就是:
Stripe::Charge.create(:amount => (self.order_sum.to_f*100).to_i, :currency => 'usd', :source => card.id, :customer => self.deposit.user.stripe_customer_id)
另外,你的控制器create方法里调用了两次@cash_in_order.save,第一次在if current_user...判断里,第二次在respond_to块里,这会导致重复执行保存逻辑,建议去掉第一次的@cash_in_order.save,只保留respond_to里的判断。
内容的提问来源于stack exchange,提问作者anndrew78
相关产品推荐
相关产品推荐

