0

我试图在我的应用程序中实现审计线索,但由于某些要求,我无法使用任何现有的宝石或插件。重载和绕过活动记录更新

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

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

眼下我已经超负荷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 

问题的第一部分,现在是时候更新模型试图实际执行更新,这会导致一个无限循环。

我一直在寻找通过铁轨核心来源找到绕过第一个功能的最佳位置。我希望这些更新在事务内部执行,但我不确定在活动记录堆栈中开始或结束的内容。我也不想开始攻击活跃的资源。

任何建议将不胜感激。

回答

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 

UPDATE:笔者曾评论说,他们希望能够以这种模式适用于所有更新。为了达到这个目的,你可以在模型中添加一个attr_accessor,比如说“perform_updates”,默认情况下默认为零。

当您想要执行数据库更新时,首先必须将该属性设置为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回调属于它的地方更好。一旦更新在某个界面中获得批准,观察者就可以执行更新,覆盖当前存在的内容,直到可以批准另一项更改为止。如果队列中的某个对象当前有更新需要批准,则可以通知用户正在等待批准的更改等。

+0

除了已预先更新之外,这与功能很接近。我已经考虑过这样的事情,但我不认为这个解决方案会捕获所有更新。例如,update_attributes也会绕过UpdateAuditor。 – stellard 2010-02-04 21:35:34

+0

我做了你所要求的改变,但是,请阅读我的评论底部附近。 – 2010-02-06 09:32:20

+0

非常感谢您的回复。我同意覆盖默认的更新方法可能很危险,但我不知道如何使用before_update回调完成我想要做的事情。如何在创建UpdateAudit后停止更新,而不会像更新失败那样执行相同的操作? – stellard 2010-02-09 20:47:49