我想在Ruby on Rails应用程序中记录用户的操作。在观察者中访问会话的好主意吗?
到目前为止,我有一个模型观察者,在更新和创建后将日志插入数据库。为了存储哪个用户执行了记录的操作,我需要访问会话,但这是有问题的。
首先,它打破了MVC模型。其次,技术从恶作剧到奇怪,甚至可能将实施与Mongrel服务器捆绑在一起。
什么是正确的方法?
我想在Ruby on Rails应用程序中记录用户的操作。在观察者中访问会话的好主意吗?
到目前为止,我有一个模型观察者,在更新和创建后将日志插入数据库。为了存储哪个用户执行了记录的操作,我需要访问会话,但这是有问题的。
首先,它打破了MVC模型。其次,技术从恶作剧到奇怪,甚至可能将实施与Mongrel服务器捆绑在一起。
什么是正确的方法?
我觉得这是一个非常有趣的问题。我会在这里大声地想一想......
最终,我们面临的是决定违反设计模式可接受的实践,以实现一组特定的功能。因此,我们必须问自己
1)什么是将不违反MVC模式
2)什么是将违反MVC模式
3可能的解决方案可能的解决方案)哪个选项最好?我认为设计模式和标准实践非常重要,但同时如果坚持让它们使您的代码更加复杂,那么正确的解决方案很可能违反了实践。有些人可能会不同意我的看法。
让我们先考虑#1。
关闭我的头顶,我认为以下可能的解决方案
A)如果你是谁是执行这些操作,应此数据存储模型中的任何方式真正感兴趣的?它会将这些信息提供给您的观察员。这也意味着你的ActiveRecord类的其他前端调用者可以获得相同的功能。 B)如果你不是真正有兴趣了解谁创建了一个条目,但更感兴趣的是自己记录Web操作,那么你可能会考虑“观察”控制器的操作。自从我引入Rails源代码以来,已经有一段时间了,所以我不确定他们的ActiveRecord :: Observer是否“观察”了模型,但是您可能可以将其调整为控制器观察者。从这个意义上讲,您不再观察模型,并且将会话和其他控制器类型的数据信息发送给该观察者是有意义的。 C)最简单的解决方案,用最少的“结构”,就是简单地将你的日志代码放在你正在观察的动作方法的最后。
现在考虑选项#2,打破MVC的做法。
A)正如你所建议的,你可以找到让你的模型观察者有权访问会话数据的方法。您已将您的模型与业务逻辑相结合。
B)可没想到这里的任何人:)
我个人的倾向,而不用知道了细节你的项目,或者是1A,如果我要附加的人的记录,或1C如果有只有几个我对此感兴趣的地方。如果您真的想为您的所有控制器和操作提供强大的日志记录解决方案,则可以考虑1B。
让模型观察者发现会话数据有点“臭”,如果您尝试在任何其他项目/情境/上下文中使用您的模型,可能会中断。
你是对的,它打破了MVC。我建议在你的控制器中使用回调函数,主要是因为有些情况(比如一个保存被调用但验证失败的模型),你不希望观察者记录任何东西。
这是一个棘手的情况。你几乎要违反MVC才能很好地工作。
我会做这样的事情:
class MyObserverClass < ActiveRecord::Observer
cattr_accessor :current_user # GLOBAL VARIABLE. RELIES ON RAILS BEING SINGLE THREADED
# other logging code goes here
end
class ApplicationController
before_filter :set_current_user_for_observer
def set_current_user_for_observer
MyObserverClass.current_user = session[:user]
end
end
这是一个有点哈克,但比许多其他Rails核心的事情,我已经看到了它没有更多的哈克。
所有你需要做的(如果你在JRuby上运行反正这只是问题),使其线程是改变cattr_accessor是一个适当的方法,并将它保存它在线程本地存储数据
在过去,当做这样的事情时,我倾向于扩展用户模型类以包含'当前用户'的想法
看看以前的答案,我看到建议来存储实际活动记录用户在会话中。这有几个缺点。
因此,在请求开始时(在过滤器中),您从会话获取user_id并读取用户,并设置User.current_user。
事情是这样的......
class User cattr_accessor :current_user end class Application before_filter :retrieve_user def retrieve_user if session[:user_id].nil? User.current_user = nil else User.current_user = User.find(session[:user_id]) end end end
从那时起,它应该是微不足道的。
我找到了一个干净的方式来完成我选择的答案建议的内容。
http://pjkh.com/articles/2009/02/02/creating-an-audit-log-in-rails
此解决方案使用审计日志模型以及一个TrackChanges模块来跟踪功能添加到任何模型。它仍然需要您在更新或创建时向控制器添加一行。
我想到的可能是1A的东西,也许是因为它的简单性。 – Jaryl 2008-09-25 15:29:23