这段代码如何引发ActiveRecord::ReadOnlyRecord异常?

5

我有一个Purchase模型,它has_oneCoupon

Purchase模型包含以下代码:

def decrement_coupon
  coupon = Coupon.find_by_code(coupon_code, :readonly => false)
  return unless coupon.respond_to?(:uses)
  coupon.uses = coupon.uses - 1
  coupon.save
end

但是我前几天遇到了这个错误:
ActiveRecord::ReadOnlyRecord - ActiveRecord::ReadOnlyRecord:
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/persistence.rb:245:in `create_or_update'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/callbacks.rb:273:in `create_or_update'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activesupport-3.0.6/lib/active_support/callbacks.rb:419:in `_run_save_callbacks'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/callbacks.rb:273:in `create_or_update'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/persistence.rb:39:in `save'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/validations.rb:43:in `save'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/attribute_methods/dirty.rb:21:in `save'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/transactions.rb:240:in `save'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/transactions.rb:292:in `with_transaction_returning_status'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/transactions.rb:207:in `transaction'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/transactions.rb:290:in `with_transaction_returning_status'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/transactions.rb:240:in `save'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/transactions.rb:251:in `rollback_active_record_state!'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/transactions.rb:239:in `save'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/associations/association_proxy.rb:222:in `send'
 /usr/local/rvm/gems/ree-1.8.7-2010.02@lyconic/gems/activerecord-3.0.6/lib/active_record/associations/association_proxy.rb:222:in `method_missing'
 /var/www/88tactical_production/releases/20110823232510/app/models/purchase.rb:69:in `decrement_coupon'
< p > :readonly => false是否不能保证记录不是只读的?将此函数移至Coupon模型是否会有所区别?(无论如何,我可能会这样做)


不是答案,但你尝试过 Coupon.readonly(false).find_by_code(code) 吗?我不记得看到 :readonly 选项被正式弃用,但我相信使用类似作用域的 Model.readonly 方法是“Rails 3 Way”。 - numbers1311407
在我的测试中,这两者之间没有区别,而且我认为我没有收到弃用警告。 - Adam Lassek
1个回答

12

这可能是由于您的 find_by_code() 帮助程序通过加入其他子值而导致的。

当 ActiveRecord 使用 joins 查找对象并返回附加值时,它会将该记录标记为只读。

关于此问题有一个详细的描述,请参见此问题

如果是这种情况,您可以通过将您的 :joins 转换成适当的 :include 来解决问题,从而在不标记它们为只读的情况下填充 ActiveRecord 实例。


1
Coupon 的默认作用域确实有一个 joins 调用。让我困惑的是,在控制台中显式传递 :readonly => false 是可行的,但无论如何在生产环境中都会出错。 - Adam Lassek
这是一个操作顺序的问题 - 你关闭了read_only,但在处理ActiveRecord时(在使用默认false值后),它会将其设置为true,因为你传递了一个:joins参数。 - Winfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接