实例及其关联的审计和模型生命周期管理?

时间:2009-10-23 21:25:17

标签: ruby-on-rails logging associations nested-forms auditing

我正在尝试编写一个应用程序来跟踪法律案件请求。主要模型是Case,has_many主题,关键词,注释和证据(反过来,has_many CustodyLogs)。由于申请与法律有关,因此有一些不寻常的要求:

  • 必须记录CRUD操作,包括操作内容,操作员是谁以及操作何时发生
  • 需要某种方式来验证数据(即记录记录的MD5校验和)
  • 某些数据应该是一次性写入(即应用程序可以创建审核日志条目,但此后无法在应用程序中编辑或删除该日志)
  • 可能应在整个嵌套过程中记录对关联对象的更改。例如,在一段证据中添加一个CustodyLog应该有一个自己的日志,一个日志,它的证据,以及一个父案例的日志。这是为了确保Case的最后更新时间戳准确反映真实的上次更新,而不仅仅是Case模型数据本身最后一次更改的时间。

我有点工作,但我遇到了问题。身份验证由外部Web单点登录服务处理,因此对登录用户的ID的唯一可见性在请求变量中。例如,如果我通过回调将审计日志记录放入模型中,我可以相当确定所有数据修改都已记录,但模型对请求变量没有可见性,因此我无法记录用户ID。这还可以确保记录对状态机(当前使用state_machine插件)的更改。

另一方面,如果我将审计日志记录放在应用程序控制器中,我将无法确保记录所有CRUD操作(例如,调用Subject.create的Case模型中的代码不会记录)。我也认为我会失去状态变化。

有没有办法确保在整个关联树中记录所有CRUD操作,以便记录登录用户的用户ID?

1 个答案:

答案 0 :(得分:0)

必须记录CRUD操作,包括操作内容,操作员是谁以及操作何时发生

可以使用ActiveRecord :: Callbacks和attr_accessor字段来解决这个问题。

在需要记录的任何模型中添加以下内容。

  attr_accessor :modifier_id, :modifier

  valiadate :valid_user
  before_validate :populate_modifier
  before_save :write_save_attempted_to_audit_log
  after_save :write_save_completed_to_audit_log

  def populate_modifier
    self.modifier = User.find_by_id(modifier_id) unless modifier
  end 

  def valid_user
    unless modifier
      errors.add(:modifiers_user_id, "Unknown user attempted to modify this record") 
      write_unauthorized_modification_to_audit_log
    end
  end

  def write_save_attempted_to_audit_log
    # announce that user is attempting to save a record with timestamp to audit log
    # use ActiveRecord::Dirty.changes to show the change the might be made
  end

  def write_save_competed_to_audit_log
    # announce that user has successfully changed the record with timestamp to audit log
  end

  def write_unauthorized_modification
    # announce that a change was attempted without a user
  end

因为您可能会在一些模型中使用它,所以您可以将其抽象为插件,并仅在需要时使用audit_changes之类的方法调用添加它。查看任何acts_as插件,了解如何实现此目的。

在控制器中,您需要记住在尝试保存之前添加@thing.modifier = @current_user


需要某种方法来验证数据(即记录记录的MD5校验和)

关于操作的校验和?您可以覆盖inspect以一致的方式打印包含记录中所有信息的字符串,然后为其生成校验和。当你在它的时候,不妨把它作为写入日志方法的一部分添加到审计日志中。


某些数据应该是一次性写入(即应用程序可以创建审核日志条目,但此后无法在应用程序中编辑或删除该日志)

将每个访问日志写为具有确定名称("/logs/audits/#{class}/#{id}/#{timestamp}")的单独文件,并在保存后删除写入权限。 File.chmod(0555, access_log_file)


可能应在整个嵌套过程中记录对关联对象的更改。例如,在一段证据中添加一个CustodyLog应该有一个自己的日志,一个日志,它的证据,以及一个父案例的日志。这是为了确保Case的上次更新时间戳准确反映实际的上次更新,而不仅仅是上次Case模型数据本身更改的时间。

关于第4项要求。如果您在任何嵌套关系上使用accepts_nested_attributes_for,那将自动进入我的第一个解决方案。并且:autosave =>对于belongs_to关系,则为true。


如果要将校验和保存到审核日志中,则可以将检查信息转入before_save方法,以确保您正在处理的对象未被篡改。只需检查对象的最新审核日志并匹配校验和即可。