mongoid不可变记录

时间:2013-01-15 13:00:27

标签: ruby-on-rails mongoid

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

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

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

谢谢!

2 个答案:

答案 0 :(得分:1)

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

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

第一次在新save上致电createJob时,数据会成功保留。当您致电save时,对象的进一步更改将不会写入数据库。 delete的行为不会受到影响。

为什么会这样?

如果返回false,则

before_validation取消持久性:

  

如果before_validation回调的返回值可以被评估为false,则进程将被中止,Base#save将返回false。如果ActiveRecord :: Validations#save!被调用它会引发一个ActiveRecord :: RecordInvalid异常。什么都不会附加到错误对象。

方法参考

    如果任何字段为脏,则
  1. changed?返回true

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

答案 1 :(得分:0)

我扩展了塞巴斯蒂安的excellent answer以使行为更加清晰。

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_validationCalling update_attributes! on Job resulted in a false return from a callback.
  2. 获得的解释更为明确
  3. 它遵循not using callbacks for domain logic上的Mongoid建议:使用域逻辑的回调是一种糟糕的设计实践,并且可能导致在链中的回调暂停执行时难以调试的意外错误。我们建议仅将它们用于横向关注问题,例如排队后台工作。