2

如,freeze禁用更新对象值的能力(在一定程度上)。我如何构建一个方法User.disable_persistence来禁用在该对象和关联对象上创建/保存/更新的能力,直接调用(User.save)和间接调用(User.children << child)。

是否有宝石或简单的方法,例如:

class User < ...
  def disable_persistence
    # magic here (nullify save, and other methods, prevent callbacks etc.)
    class_eval :before_save do 
      errors.add(:base, "Persistence has been disabled for this object")
    end
  end
end
4

3 回答 3

2

问题看起来很简单。棘手的部分是and indirectly (User.children << child)它的一部分。User当父对象 ( ) 是新记录时,这可以很容易地处理。但如果不是,就不会那么容易。这是因为像这样的语句user#children << child保存了父记录,并且children当记录user是新的时,当它不是时不做同样的事情。在后一种情况下,它只保存child. 这个问题在这个项目上没有自动解决,至少现在是这样。开发人员必须首先禁用child对象的持久性才能在后一种情况下实现这一点。

查看author_spec.rb文件。告诉你整个故事非常有帮助。

我为回答您的 SOW 问题而开发的整个项目都在这里:https ://github.com/pmatsinopoulos/disable_persistence

任何想为此做出贡献的人,请随意。

为了方便读者,这里也引用了完成整个技巧的代码:

disable_persistence.rb文件:

module DisablePersistence
  extend ActiveSupport::Concern

  def disable_persistence
    @persistence_disabled = true
  end

  def enable_persistence
    @persistence_disabled = false
  end

  module ClassMethods
    def disable_persistence
      @@class_persistence_disabled = true
    end

    def enable_persistence
      @@class_persistence_disabled = false
    end

    def persistence_disabled?
      @@class_persistence_disabled ||= false
    end

    def persistence_disabled
      persistence_disabled?
    end
  end

  included do
    attr_reader :persistence_disabled
    alias :persistence_disabled? :persistence_disabled

    before_save :can_persist?

    after_initialize do |base|
      base.instance_variable_set(:@persistence_disabled, false)
    end

    def can_persist?
      !persistence_disabled? && !self.class.persistence_disabled?
    end

    protected :can_persist?
  end
end

ActiveRecord::Base.send :include, DisablePersistence

笔记:

A. 实例将响应:

  1. #disable_persistence
  2. #enable_persistence
  3. #persistence_disabled?

B. 班级将回应:

  1. #disable_persistence
  2. #enable_persistence
  3. #persistence_disabled?

C. 有一种protected before_save方法可以检查实例是否可以持久化。它检查是否启用了实例和类持久性。如果有任何被禁用,则不允许实例持续存在。

D. 该功能自动包含在所有ActiveRecord::Base类中。这是上面的最后一行。你可能不想要那个。如果您不希望这样,您必须调用您想要此功能的include DisablePersistence所有课程。ActiveRecord::Base

E. 在我链接到的 rails 项目中,我有一个initializer包含require此代码的文件。查看config/initializers. 否则,您将不得不自己要求它。

一些使用示例(假设作者和他们的书):

第一个例子:

author = Author.new
author.disable_persistence
author.save # will return false and nothing will be saved
author.enable_persistence
author.save # will return true and author will be saved

第二个例子:

author = Author.new
author.disable_persistence
book = Book.new
author.books << book
author.save # false and nothing will be saved

第三个例子:

author = Author.new
author.save
book = Book.new
book.disable_persistence
author.books << book # nothing will be saved

第四个例子:

author = Author.new
author.save
book = Book.new
author.disable_persistence
author.books << book # will be saved indeed, because the book has enabled persistency

第五个例子:

author = Author.new
Author.disable_persistence
author.save # will return false and will not save

我希望以上内容能回答您的问题,或者至少在某种程度上有所帮助。

于 2013-07-27T05:21:25.353 回答
2

如果设置为 false,您可以添加一个过滤器来检查重定向到根 urlbefore_save的布尔字段(例如)的值。editable该块将在create/save/update调用方法之前结束。

于 2013-07-26T19:49:00.683 回答
1

您可以创建一个事务并为回滚任何更改抛出一个异常。

于 2013-07-26T20:12:31.763 回答