2009-07-06 53 views
2

在我的Rails應用中,我想跟蹤誰更改我的模型並更新模型表上的字段以反映。在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中破壞這些數據嗎?

從控制器傳遞這些信息是否更好?

回答

2

最佳做法是讓你的模型是無狀態的,控制器獲取處理狀態。如果你想讓這些信息到達你的模型,你需要從控制器傳遞它。在這裏使用創建鉤子並不是真正正確的方法,因爲您正在嘗試添加有狀態數據,而這些鉤子確實適用於無狀態行爲。

您可以從控制器傳遞信息中:

Foo.new(params[:foo].merge {:creator_id => current_user.id}) 

或者,您可以創建方法上的用戶來處理這些操作:如果您發現自己寫了很多的權限代碼

class User 
    def create_foo(params) 
    Foo.new(params.merge! {:creator_id => self.id}) 
    end 
end 

在控制器中,我會使用選項2,因爲它會讓您將該代碼重構爲模型。否則選項1更清潔。

奧馬爾指出,它自動化很棘手,但它仍然可以完成。這裏有一種方法,使用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的方法,它包裝新。

有可能是一種更優雅的方式來做事情,但我絕對不喜歡嘗試從模型代碼中讀取狀態,它打破了MVC封裝。我更喜歡以某種方式明確地傳遞它。

0

我會創建新的保存,更新等方法,從調用它們的所有東西(主要是控制器)中獲取user_id。

我可能會將ActiveRecord:Base擴展爲一個新的類,以處理需要此行爲的所有模型。

0

我不信任Thread.current,看起來有點ha。。我總是會調用一個需要參數的自定義方法:

def create_with_creator(creator, attributes={}) 
    r = new(attributes) 
    r.creator = creator 
    r.save 
end 

因爲它遵循MVC模式。這顯然是一個遺傳問題,因爲你要在任何地方打電話給create_with_creator

0

您可能會發現PaperTrail有用。

+0

它避免了執行Thread.current,但使用全局變量和中央模塊來跟蹤當前用戶。 – 2009-07-06 11:47:21

+0

它現在使用Thread.current。 – 2010-11-04 08:25:37

1

是啊,這樣的事情會工作,或在您的控制器上的用戶模型有一個類變量

cattr_accessor :current_user 

然後你可以有這樣的:過濾器之前

User.current_user = current_user 

內(假設current_user是登錄用戶)。

然後,您可以擴展AR:Base的create/update方法來檢查模型上是否存在created_by/updated_by字段,並將該值設置爲User.current_user

+0

我想如果你不關心線程安全。 – 2009-07-07 04:38:21