在我的rails应用程序中,我想跟踪谁更改我的模型并更新模型表上的字段以反映。
所以,例如我们有:
class Foo < ActiveRecord::Base
before_create :set_creator
belongs_to :creator, :class_name => "User"
protected
def set_creator
# no access to session[:user_id] here...
end
end
从我的模型中获取user_id对我来说有什么好的可测试方法?我应该在Thread.current中解决这些数据吗?
从控制器处传递此信息是否更好?
答案 0 :(得分:2)
MVC的最佳实践是让你的模型无状态,控制器处理状态。如果您希望信息到达模型,则需要从控制器传递信息。在这里使用创建挂钩并不是正确的方法,因为您正在尝试添加有状态数据,而这些挂钩实际上是用于无状态行为。
您可以从控制器传递信息:
Foo.new(params[:foo].merge {:creator_id => current_user.id})
或者您可以在User上创建方法来处理这些操作:
class User
def create_foo(params)
Foo.new(params.merge! {:creator_id => self.id})
end
end
如果您发现自己在控制器中编写了大量权限代码,我会使用选项2,因为它可以让您将该代码重构为模型。否则选项1更清晰。
奥马尔指出,自动化比较棘手,但仍然可以完成。这是一种方法,在user上使用create_something实例方法:def method_missing(method_sym, *arguments, &block)
meth = method_sym.to_s
if meth[0..6] == "create_"
obj = meth[7..-1].classify.constantize.new(*arguments)
obj.creator_id = self.id
else
super
end
end
你也可以覆盖构造函数以在构造时要求user_ids,或者在ApplicationController中创建一个包装new的方法。
可能有一种更优雅的方式来做事,但我绝对不喜欢尝试从模型代码中读取状态,它打破了MVC封装。我更喜欢明确地以某种方式传递它。
答案 1 :(得分:1)
是的,类似的东西可以使用,或者在你的用户模型上有一个类变量
cattr_accessor :current_user
然后在你的控制器中你可以有类似的东西:
User.current_user = current_user
在过滤器内部(假设current_user是登录用户)。
然后,您可以扩展AR:Base的create/update
方法,以检查模型上是否存在created_by/updated_by
字段,并将值设置为User.current_user
。
答案 2 :(得分:0)
我创建了新的保存,更新等方法,这些方法从调用它们的所有内容(主要是控制器)中获取user_id。
我可能会将ActiveRecord:Base扩展为一个新类,为需要此行为的所有模型处理此问题。
答案 3 :(得分:0)
我不相信Thread.current,似乎有点hackish。我总是会调用一个带有参数的自定义方法:
def create_with_creator(creator, attributes={})
r = new(attributes)
r.creator = creator
r.save
end
遵循MVC模式。这个显而易见的问题是,你将在任何地方调用create_with_creator
。
答案 4 :(得分:0)
您可能会发现PaperTrail有用。
答案 5 :(得分:0)
也许你可以查看usertamp插件,在github中找到两个
http://github.com/delynn/userstamp/tree/master http://github.com/jnunemaker/user_stamp/tree/master