自动跟踪Rails中的模型更改

时间:2009-07-06 05:18:00

标签: ruby-on-rails ruby

在我的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中解决这些数据吗?

从控制器处传递此信息是否更好?

6 个答案:

答案 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