如何为每个表创建一个完整的审计日志登录轨道? -- ruby-on-rails 领域 和 ruby 领域 和 activerecord 领域 和 observer-pattern 领域 相关 的问题

How to create a full Audit log in Rails for every table?


简体版||繁體版
20
vote

问题

中文

我们最近开始推动我们公司,并且需要对我们的数据进行完整的更改历史,目前在Rails应用程序中管理。我们已经获得了OK,只需推动对日志文件的每个动作的描述性,这是一种相当不引人注目的方式。

我的倾向是在 ApplicationController

中做这样的事情
  around_filter :set_logger_username  def set_logger_username   Thread.current["username"] = current_user.login || "guest"   yield   Thread.current["username"] = nil end   

然后创建一个看起来像这样的观察者:

  class AuditObserver < ActiveRecord::Observer   observe ... #all models that need to be observed    def after_create(auditable)     AUDIT_LOG.info "[#{username}][ADD][#{auditable.class.name}][#{auditable.id}]:#{auditable.inspect}"   end    def before_update(auditable)     AUDIT_LOG.info "[#{username}][MOD][#{auditable.class.name}][#{auditable.id}]:#{auditable.changed.inspect}"   end    def before_destroy(auditable)     AUDIT_LOG.info "[#{username}][DEL][#{auditable.class.name}][#{auditable.id}]:#{auditable.inspect}"   end    def username     (Thread.current['username'] || "UNKNOWN").ljust(30)   end end   

一般而言,这工作 great ,但它在使用"魔术" <association>_ids 方法时失败,该方法被加到has_many:通过=&gt;关联。

例如:

  # model class MyModel   has_many :runway_models, :dependent => :destroy   has_many :runways, :through => :runway_models end  #controller class MyModelController < ApplicationController    # ...    # params => {:my_model => {:runways_ids => ['1', '2', '3', '5', '8']}}    def update     respond_to do |format|       if @my_model.update_attributes(params[:my_model])         flash[:notice] = 'My Model was successfully updated.'         format.html { redirect_to(@my_model) }         format.xml  { head :ok }       else         format.html { render :action => "edit" }         format.xml  { render :xml => @my_model.errors, :status => :unprocessable_entity }       end     end   end    # ... end   

这将结束触发 after_create 当新 Runway 记录相关联时,但不会触发 before_destroy 当<代码> RunwayModel 已删除。

我的问题是... 有没有办法让它工作,以便它将观察到这些变化(和/或潜在的其他删除)?
是否有更好的解决方案仍然相对不引人注目?

英文原文

We recently began a compliance push at our company and are required to keep a full history of changes to our data which is currently managed in a Rails application. We've been given the OK to simply push something descriptive for every action to a log file, which is a fairly unobtrusive way to go.

My inclination is to do something like this in ApplicationController:

around_filter :set_logger_username  def set_logger_username   Thread.current["username"] = current_user.login || "guest"   yield   Thread.current["username"] = nil end 

Then create an observer that looks something like this:

class AuditObserver < ActiveRecord::Observer   observe ... #all models that need to be observed    def after_create(auditable)     AUDIT_LOG.info "[#{username}][ADD][#{auditable.class.name}][#{auditable.id}]:#{auditable.inspect}"   end    def before_update(auditable)     AUDIT_LOG.info "[#{username}][MOD][#{auditable.class.name}][#{auditable.id}]:#{auditable.changed.inspect}"   end    def before_destroy(auditable)     AUDIT_LOG.info "[#{username}][DEL][#{auditable.class.name}][#{auditable.id}]:#{auditable.inspect}"   end    def username     (Thread.current['username'] || "UNKNOWN").ljust(30)   end end 

and in general this works great, but it fails when using the "magic" <association>_ids method that is tacked to has_many :through => associations.

For instance:

# model class MyModel   has_many :runway_models, :dependent => :destroy   has_many :runways, :through => :runway_models end  #controller class MyModelController < ApplicationController    # ...    # params => {:my_model => {:runways_ids => ['1', '2', '3', '5', '8']}}    def update     respond_to do |format|       if @my_model.update_attributes(params[:my_model])         flash[:notice] = 'My Model was successfully updated.'         format.html { redirect_to(@my_model) }         format.xml  { head :ok }       else         format.html { render :action => "edit" }         format.xml  { render :xml => @my_model.errors, :status => :unprocessable_entity }       end     end   end    # ... end 

This will end up triggering the after_create when new Runway records are associated, but will not trigger the before_destroy when a RunwayModel is deleted.

My question is... Is there a way to make it work so that it will observe those changes (and/or potentially other deletes)?
Is there a better solution that is still relatively unobtrusive?

           
 
 

回答列表

10
 
vote

我对最近的项目有类似的要求。我使用 acts_as_audited gem,它适合我们。

在我的应用程序控制器中,我有像以下的线条

  audit RunWay,RunWayModel,OtherModelName   

并照顾所有魔法,它也会记录所做的所有变化,谁制造它们 - 它的漂亮光滑。

希望它有助于

 

I had a similar requirement on a recent project. I ended using the acts_as_audited gem, and it worked great for us.

In my application controller I have line like the following

audit RunWay,RunWayModel,OtherModelName 

and it takes care of all the magic, it also keeps a log of all the changes that were made and who made them-- its pretty slick.

Hope it helps

 
 
 
 
6
 
vote

使用 vestale版本插件

参考此屏幕为更多详细信息。看看类似问题最近在这里回答。

Vestal versions 插件是最活跃的插件,它只存储三角形。属于不同模型的三角洲存储在一个表中。

  class User < ActiveRecord::Base   versioned end  # following lines of code is from the readme     >> u = User.create(:first_name => "Steve", :last_name => "Richert") => #<User first_name: "Steve", last_name: "Richert"> >> u.version => 1 >> u.update_attribute(:first_name, "Stephen") => true >> u.name => "Stephen Richert" >> u.version => 2 >> u.revert_to(10.seconds.ago) => 1 >> u.name => "Steve Richert" >> u.version => 1 >> u.save => true >> u.version => 3   

 

Use the Vestal versions plugin for this:

Refer to this screen cast for more details. Look at the similar question answered here recently.

Vestal versions plugin is the most active plugin and it only stores delta. The delta belonging to different models are stored in one table.

class User < ActiveRecord::Base   versioned end  # following lines of code is from the readme     >> u = User.create(:first_name => "Steve", :last_name => "Richert") => #<User first_name: "Steve", last_name: "Richert"> >> u.version => 1 >> u.update_attribute(:first_name, "Stephen") => true >> u.name => "Stephen Richert" >> u.version => 2 >> u.revert_to(10.seconds.ago) => 1 >> u.name => "Steve Richert" >> u.version => 1 >> u.save => true >> u.version => 3 
 
 
 
 
2
 
vote

将此猴子补丁添加到我们的 lib/core_extensions.rb

  ActiveRecord::Associations::HasManyThroughAssociation.class_eval do    def delete_records(records)     klass = @reflection.through_reflection.klass     records.each do |associate|       klass.destroy_all(construct_join_attributes(associate))     end   end end   
它是一个绩效命中(!),但满足要求,并考虑到这一事实,即这个Destroy_all不会经常被称为,它适用于我们的需求 - 虽然我要查看Acts_As_versioned和Acts_As_Audited
 

Added this monkey-patch to our lib/core_extensions.rb

ActiveRecord::Associations::HasManyThroughAssociation.class_eval do    def delete_records(records)     klass = @reflection.through_reflection.klass     records.each do |associate|       klass.destroy_all(construct_join_attributes(associate))     end   end end 

It is a performance hit(!), but satisfies the requirement and considering the fact that this destroy_all doesn't get called often, it works for our needs--though I am going to check out acts_as_versioned and acts_as_audited

 
 
 
 
0
 
vote

你也可以使用acts_as_versioned http://github.com/technownowee/acts_as_versioned < BR /> 它是您的表格记录并在每次更改的情况下创建副本(如在Wiki中)
这比日志文件更容易审核(在接口等中显示界面),而不是日志文件

 

You could also use something like acts_as_versioned http://github.com/technoweenie/acts_as_versioned
It versions your table records and creates a copy every time something changes (like in a wiki for instance)
This would be easier to audit (show diffs in an interface etc) than a log file

 
 

相关问题

1  Magento:登录过程前的火灾活动  ( Magento fire event before the login process ) 
读过一些帖子后,我试图在用户登录前实施观察者以启动事件。我会解释:我有一个论坛和一个博客,使用另一个框架,我希望访问者只记录一次:博客,论坛或eShop。之后,他将被记录为其他领域。例如,我正在浏览论坛,我登录论坛。然后,当我打开商店时,我已经登录了。相同的是相反的方式。 它有效,但只是一个问题:当我登录论坛/博客...

2  来自天然C ++的观察者模式到C ++ / CLI  ( Observer pattern from native c to c cli ) 
我有一段代码(本机)c ++,现在我必须用c#gui应用程序集成它。我已经在C ++ / CLI中构建了包装器,我可以通过此包装器成功地与本机代码进行通信。然而,问题是,此本机C ++代码使用观察者模式,我可以" t赚到工作。我看看这个类似的问题,但通过a解决了C ++ / CLI组件的通知。通过a代表。我无法观察到...

3  将其他信息传递给ActionMailer观察者  ( Pass additional information to actionmailer observer ) 
我需要保存有关在数据库中向我的客户发送每封电子邮件的信息以进行进一步分析。所以我正在尝试在观察者中做到这一点,但我需要关于发票的信息。 所以我有邮件: class ClientMailer < ActionMailer::Base default :from => "no-reply@tori-app.her...

3  iPhone MKMAPVIEW注释观察员可选一次  ( Iphone mkmapview annotations observers selectable once ) 
我在mkmapview上有不同的自定义映射注释,并且在创建自定义视图时,我添加观察者并禁用默认弹出窗口。 在MapViewController.m的顶部: static NSString* const ANNOTATION_SELECTED_DESELECTED = @"annotationSelectedOrD...

5  在网络上观察者  ( Observer over a network ) 
我希望有一个事件驱动的架构,其中活动消费者(订阅者/观察者)和事件制作人(发布者/主题)在分布式地理上。 是有关.NET的东西,无缝地在网络上缩短事件,而无需我必须拆进传输机制的实现? 我召回juval yowy说些关于企业服务的DNR显示2年左右的东西,但不能记得那是什么。 任何人都知道我可以从.NET Frame...

3  如何通过观察者调用外部逻辑时保护数据结构一致性?  ( How to guard data structure consistency when calling external logic via observer ) 
我目前重构了一个应用程序,其中类可以调用观察者如果他们的状态发生变化。这意味着只要:,观察者被调用 实例中的数据类更改 类的新实例是创建 类的实例被删除 这是最后一个让我担心的案例。 假设我的班级是书。观察者存储在一个名为BookManager(BookManager还保留所有书籍的类)。这意味着我们有这个: ...

9  最佳发布/订阅“中间件”[已关闭]  ( Best publish subscribe middleware ) 
关闭。这个问题不符合堆栈溢出指南。它目前不接受答案。 想要改进这个问题?更新问题,所以它是关于堆栈溢出的主题。 关闭 7年前。 ...

34  在JSON中传递函数并执行  ( Pass function in json and execute ) 
是有没有方法可以将函数传递为json字符串(与json.stringify转换),将其发送到另一个函数,解析JSON,然后执行json中的函数?我正在使用jQuery和JavaScript。 ...

1  Ember.js + jQuery-UI工具提示 - 工具提示不反映模型/控制器更改  ( Ember js jquery ui tooltip tooltip does not reflect the model controller c ) 
上下文 我有一个小型ember应用程序,其中,其中,在其他事情中,显示了许多连接的用户,并且在将页面的元素悬停时,它们的名称作为列表。 一切,它很好地工作。应用程序从每两分钟从REST端点拉动数据,因为后端不允许推送数据。 工具提示的内容在控制器中计算,具有基本上以各种方式连接字符串的函数根据上下文。然后它绑定到 ...

1  原型:文档键盘,换句话时间停止观察  ( Prototype keydown on document stop observing when in form ) 
我正在尝试使用ajax左/右箭头键工作(如facebook上)使用ajax进行下一个/上一页。一切都很好,有效,但我也有表格在我的页面上,如果用户专注于该表单,我想停止观察左/右键,因为没有你不能在表单中用箭头移动,你正在下一个/以前的图像而不是形式的运动。 我的实际代码在这里,commend_name是字段的ID,...

1  将nsnotificeCenter设计模式移动到C ++以移植?  ( Moving nsnotificationcenter design pattern to c for porting ) 
我即将从iPhone obj-c开始将相对大的游戏移植到平台中性C ++。在我们的游戏中,我们大量使用 NSNotificationCenter ,用于了解我们的服务器的菜单和游戏和缓存更新。 我正在考虑使用Singleton类重新创建 NSNotificationCenter ,然后使用任何类接收通知的类继承了通知...

5  观察者设计模式  ( Observer design pattern ) 
在观察者设计模式中,主题通过调用每个观察者的 update() 操作来通知所有观察者。这样做的一种方法是 docker-compose down0 但是这里的问题是每个观察者在序列中更新,并且在更新之前,可能不会调用观察者的Observer的更新操作。如果有一个具有无限循环的观察者,则将永远不会通知所有观察者...

1  持久性模式 - 基于规则的观察者  ( Persistence pattern rule based observer ) 
我正在尝试向应用程序添加功能,其中用户可以订阅所做的更改: 到另一个实体(由任何用户) 由另一个用户(到任何其他实体) 两者的组合(最后一个是可选的,而是使问题更具挑战性) 我想知道如何最好将这些规则持续到数据库。 我自然倾向于每个给定的实体(包括用户本身),我添加了加法用户库表/实体(例如,PublisherU...

5  是迟复的听众可以在JavaScript中预防?  ( Are lapsed listeners preventable in javascript ) 
我的问题真的"是失效的侦听器问题在javascript中可以预防?" 但显然"问题" 这个词会导致问题。 wikipedia page说失误的侦听器问题可以通过拍摄的主题弱引用对观察者。我以前在Java之前实现了,它很好地工作,我以为我会在JavaScript中实现它,但现在我没有看到如何。 JavaScript甚...

1  XPCOM / Jetpack观察所有文档负载  ( Xpcom jetpack observe all document loads ) 
我在加载文档时写入的基于Mozilla Jetpack的加载项。对于"toplevel文件" 这主要使用此代码( 99887663 ): this.endDocumentLoadCallback = function (subject, data) { console.log('loade...

0  每次值更改运行方法  ( Run a method everytime value changes ) 
我想知道你们中的任何人是否可以帮助我想到我认为的问题。 我有一个元素(SVG更具体),我想每次改变某处的值时更新。 我有变量: GetThreadTree().treeBoxObject.getFirstVisibleRow() 最初是0.我想运行 function updateCanvas() GetThr...

0  Rails延迟作业访问后台工作的价值  ( Rails delayed job accessing value of background job ) 
在我的Rails应用程序中,我每秒都有一个定时器滴答,基于哪个不同的对象改变了他们的状态。因此,我决定使用观察者。但是,当我跑了观察者时,我注意到它挂断了我的整个应用程序,直到定时器完成。因此,我正在考虑使用delayed_job保持定时器作为后台作业。 现在我的查询是有没有办法从每秒获取计时器的值并将其用于控制​​...

2  使用Spring XML配置实现观察者模式?  ( Implement observer pattern with spring xml config ) 
假设bean A 是事件发布者(可观察)和bean B1 , B2 和 B3 是活动侦听器(观察员)。 所有bs实现一些 BEvenListener 界面。 如何在 A 中代码可观察界面?我希望代码常见的Java's addEventListener(BEventListener listener) 。 如...

6  如何触发在Magento收到的付款的活动?  ( How to trigger an event on payment received in magento ) 
问候,在magento我想触发一个事件,一旦订单已经设置为处理(通过网关确认或手动),示例:如果一般客户(ID 1)花费超过100美元并付款确认,将其组ID设置为4(Silver VIP,通过促销规则全球折扣2%) 我会给这个赏金,但我想在2天之前答案O_o 编辑:我收到的答案到目前为止只是一个部分答案,我也发现...

1  Java - 对于动画,逻辑类应该如何通知重新粉刷的松散耦合的视图  ( Java for an animation how should a logic class notify a loosely coupled view ) 
对于经常重绘的应用程序,"模型" 应该如何通知"视图" ,以便他们需要重复重写其组件之一。这个: class AppLogic extends Observable { void runAnimation() { while (isAnimationRunning) { modify...

10  在Rails中,一个扫除程序没有被称为纯粹的设置  ( In rails a sweeper isnt getting called in a model only setup ) 
我正在使用Rails应用程序,在那里我正在使用页面缓存来存储静态HTML输出。缓存工作正常。但是,我在缓存中遇到了麻烦。 我相信我的问题是部分原因是因为我没有从我的控制器中到期缓存。在模型中处理此类所需的所有行动。这似乎应该是可行的,但是所有对模型的高速缓存到期的引用都是在我发现的基于模型的缓存到期似乎是超出日期,或...

40  在耙任务期间关闭观察者的简单方法?  ( Simple way of turning off observers during rake task ) 
我在我的应用程序中使用restful_authentication。我正在使用rake任务创建一组默认用户,但每次运行任务时,由于与我的用户模型关联的观察者,发送激活电子邮件。我在创建用户时,我会设置激活字段,所以不需要激活。 任何人都知道在运行Rake任务时绕过观察者的简单方法,以便在保存用户时没有发送电子邮件?...

17  iPhone:Camera自动对焦观察者吗?  ( Iphone camera autofocus observer ) 
我想知道是否可以在iPhone应用程序内接收有关自动对焦的通知? i.E,如果自动对焦启动,结束,如果它成功或失败,则是否存在通知的方法...? 如果是这样,这个通知名称是什么? ...

0  多个观察者和多个可观察到  ( Multiple observer and multiple observable ) 
我正在使用Java中的可观察类/观察者接口来实现观察者模式。如果我有一个物体,我希望能够观察几个其他可观察对象(多个观察到)并具有多个观察者(多个观察者) 问题在b类中不是AnobServable,但我希望在A和B中值为生成图表 public void update(Observable anObservable...

4  DataBinding和BaseBserver - Android MVVM  ( Databinding and baseobserver android mvvm ) 
我有一个文本字段,它是一个像XML这样的视图模型,我希望UI更新CardView的TXTProvider字段。 我该如何向我的视图中通知更改视图? <layout xmlns:bind="http://schemas.android.com/tools"> <data> <variable name="...




© 2021 it.wenda123.org All Rights Reserved. 问答之家 版权所有