如何在Rails上正确执行条件只读记录?

时间:2014-07-24 15:34:08

标签: ruby-on-rails ruby validation activerecord

因此出现了工作情况,我想在这里讨论,因为我们无法达成协议:

我们有两个模型,OrderPassport,它们与订单has_one护照和护照has_many订单相关。订单完成后,其相关护照必须被锁定,即转为只读(该信息已用于清关,因此之后无法更改)。我们希望在Passport模型中强制执行该规则,并且我们已经考虑了以下选项:

  1. 创建验证。缺点:当技术上记录正常时(虽然无法保存),会有记录产生valid? => false。例如,如果其他记录上有validates_associated :passport,则可能会出现问题。
  2. 覆盖readonly?方法。缺点:这会在尝试更新该记录时引发异常,但您可能希望调用save方法不会引发该记录。
  3. 创建before_save回调。这有两种风格:引发异常(与readonly?选项非常相似)或添加@error并返回false以停止回调链。缺点:从正确的验证外部添加验证错误可被视为不良做法。此外,您可能会发现自己正在呼叫valid?并获取true,然后致电save并获取false
  4. 这种情况使我们对验证和Rails之间的关系有很多想法。记录valid?到底意味着什么?这是否意味着save会起作用?

    我想听取您的意见,了解这种情况。也许最好的方法不是三者之一!谢谢!

2 个答案:

答案 0 :(得分:0)

使用readonly!实例方法将此记录标记为只读怎么样?请参阅API

您可以在构造函数中执行此操作,例如:

class Passport < ActiveRecord::Base
  def initialize(*args)
    super(*args)
    readonly! if orders.count>0 # or similar
  end
end

答案 1 :(得分:0)

我认为还有一个额外的选择。您所描述的内容表明Passport模型可以有一些不同的状态。我会考虑使用状态机来描述护照的相关订单状态。

例如:

  • 未决
  • 锁定
  • other_update_actions ...

考虑到这一点,所有相关的订单操作都会触发护照模型及其状态的事件。

如果可以将更新操作集成到某些事件,那么您可以以更优雅的方式处理只读部分(不兼容的状态转换)。

作为额外的检查,您可以始终将丑陋的验证器作为最后的手段,以防止在没有状态机的情况下更新模型。

您可以查看the aasm gem了解此内容