0

我正在尝试在我的应用程序中实现审计跟踪,但由于某些要求,我无法使用任何现有的 gem 或插件。

我想将更新模型的任何正常尝试转移到自定义方法,该方法将所有更新保存在另一个单独的表(称为更新)中。

然后应用程序使用更新表来实际执行更新。

现在我已经重载了 create_or_update 来获得功能的第一部分

def create_or_update
  raise ReadOnlyRecord if readonly?
  result = new_record? ? create : create_updates
  result != false
end


class Update < ActiveRecord::Base
  belongs_to :updatable, :polymorphic => true

  after_create :update_model

  private

  def update_model
    self.updatable.update_attribute self.attribute, self.new_value #infinite loop
  end
end  

现在的问题是,当更新模型尝试实际执行更新时,这会导致无限循环。

我一直在查看 Rails 核心源代码,以找到绕过第一个功能的最佳位置。我希望在事务内部执行这些更新,但我不确定在活动记录堆栈中确切的开始或结束位置。我也不想开始攻击活动资源。

任何建议将不胜感激。

4

1 回答 1

1

您是否真的需要将属性保存在单独的表中,然后在管理员查看并批准它们后执行更新?如果是这种情况,您可能只想覆盖更新方法来执行以下操作:

def update(perform_updates = false)
  if perform_updates
    latest_approved_update = UpdateAuditor.first(:conditions => { :updatable_id => self.id, :updatable_type => self.class.name, :approved => true })
    self.attributes = latest_approved_update.attributes
    self.save
  else 
    UpdateAuditor.create(:updatable_id => self.id, :updatable_type => self.class.name, :attributes => self.attributes)
  end
end

更新:作者评论说他们希望能够将此模型应用于所有更新。为了实现这一点,您可以在模型中添加一个 attr_accessor,比如说“perform_updates”,默认情况下它当然是 nil。

当您想要对数据库执行更新时,您首先必须将属性设置为 true,然后运行更新。否则,更新只会创建一个需要管理员批准的新 UpdateAuditor 记录。

class Person < ActiveRecord::Base
  has_many :audits, :class_name => "UpdateAudit", :as => :auditable

  attr_accessor :perform_updates

  private

  def create_or_update
    raise ReadOnlyRecord if readonly?

    if new_record?
      result = create
      result != false
    else
      if perform_updates
        latest_approved_update = audits.approved.last

        if latest_approved_update
          self.attributes = latest_approved_update.attributes
          update
        else
          return false
        end
      else
        audits.create(:updated_attributes => self.attributes)
      end 
    end
  end
end

作为记录,我认为覆盖默认的更新方法是一个危险的游戏,这样的编程最好before_update在它所属的回调中进行。一旦在某个界面中批准了更新,那么观察者就可以执行更新,覆盖当前存在的内容,直到可以批准所做的另一个更改。如果队列中有待批准的对象当前有更新,则可以提醒用户更改正在等待批准等。

于 2010-02-04T19:52:31.740 回答