1

我正在构建一个 Rails 3.2 应用程序,我必须将 Sidekiq 作业封装在一个单独的模型中,以维护关系并处理插入和删除。

我使用 Mongoid 作为我的主要 ORM,我想问我如何制作不可变的记录。

这意味着在(初始化和)创建作业之后,除了删除记录之外,不接受任何更改。

谢谢!

4

2 回答 2

2

假设您的 Rails 应用程序是唯一的 MongoDB 客户端,您可以在模型层实现不变性逻辑:

class Job
    include Mongoid::Document
    before_validation { false if changed? && persisted? }
end

第一次调用save或调用createnewJob时,数据将成功保存。调用时,对对象的进一步更改不会写入数据库save。的行为delete将不受影响。

为什么这有效

before_validation如果返回 false,则取消持久性:

如果 before_validation 回调的返回值可以评估为 false,则该过程将中止并且 Base#save 将返回 false。如果 ActiveRecord::Validations#save! 调用它会引发 ActiveRecord::RecordInvalid 异常。不会将任何内容附加到错误对象。

方法参考

  1. 改变了吗?如果任何字段是脏的,则返回 true

  2. 坚持?如果此对象的某个版本保存在数据库中,则返回 true

于 2013-01-16T08:42:35.837 回答
1

我扩展了塞巴斯蒂安的出色回答,以使行为更清晰。

class Job
  include Mongoid::Document

  field :msg, type: String

  validate :immutability

  def immutability
    if changed? && persisted?
      errors[:base] << "#{self.class.name} is immutable and cannot be modified after it has been persisted"
    end
  end
end

这是它的工作原理:

> job = Job.create(msg: 'Hello')
=> #<Job _id: 55a7ccb76d61634e87000000, msg: "Hello">
> job.update_attributes!(msg: 'Goodbye')
Mongoid::Errors::Validations:
Problem:
  Validation of Job failed.
Summary:
  The following errors were found: Job is immutable and cannot be modified after it has been persisted
Resolution:
  Try persisting the document with valid data or remove the validations.
        from /...
> job.destroy!
=> true

这有两个主要好处:

  1. 错误消息比您使用before_validation( Calling update_attributes! on Job resulted in a false return from a callback.)得到的解释性强得多
  2. 它遵循 Mongoid 关于不将回调用于域逻辑的建议:对域逻辑使用回调是一种糟糕的设计实践,并且可能导致在链中的回调停止执行时难以调试的意外错误。我们建议仅将它们用于横切关注点,例如排队后台作业。
于 2015-07-16T15:38:41.070 回答