2008-09-25 26 views
7

我想在Ruby on Rails應用程序中記錄用戶的操作。在觀察者中訪問會話的好主意嗎?

到目前爲止,我有一個模型觀察者,在更新和創建後將日誌插入數據庫。爲了存儲哪個用戶執行了記錄的操作,我需要訪問會話,但這是有問題的。

首先,它打破了MVC模型。其次,技術從惡作劇到奇怪,甚至可能將實施與Mongrel服務器捆綁在一起。

什麼是正確的方法?

回答

3

我覺得這是一個非常有趣的問題。我會在這裏大聲地想一想......

最終,我們面臨的是決定違反設計模式可接受的實踐,以實現一組特定的功能。因此,我們必須問自己

1)什麼是將違反MVC模式

2)什麼是違反MVC模式

3可能的解決方案可能的解決方案)哪個選項最好?我認爲設計模式和標準實踐非常重要,但同時如果堅持讓它們使您的代碼更加複雜,那麼正確的解決方案很可能違反了實踐。有些人可能會不同意我的看法。

讓我們先考慮#1。

關閉我的頭頂,我認爲以下可能的解決方案

A)如果你是誰是執行這些操作,應此數據存儲模型中的任何方式真正感興趣的?它會將這些信息提供給您的觀察員。這也意味着你的ActiveRecord類的其他前端調用者可以獲得相同的功能。 B)如果你不是真正有興趣瞭解誰創建了一個條目,但更感興趣的是自己記錄Web操作,那麼你可能會考慮「觀察」控制器的操作。自從我引入Rails源代碼以來,已經有一段時間了,所以我不確定他們的ActiveRecord :: Observer是否「觀察」了模型,但是您可能可以將其調整爲控制器觀察者。從這個意義上講,您不再觀察模型,並且將會話和其他控制器類型的數據信息發送給該觀察者是有意義的。 C)最簡單的解決方案,用最少的「結構」,就是簡單地將你的日誌代碼放在你正在觀察的動作方法的最後。

現在考慮選項#2,打破MVC的做法。

A)正如你所建議的,你可以找到讓你的模型觀察者有權訪問會話數據的方法。您已將您的模型與業務邏輯相結合。

B)可沒想到這裏的任何人:)

我個人的傾向,而不用知道了細節你的項目,或者是1A,如果我要附加的人的記錄,或1C如果有隻有幾個我對此感興趣的地方。如果您真的想爲您的所有控制器和操作提供強大的日誌記錄解決方案,則可以考慮1B。

讓模型觀察者發現會話數據有點「臭」,如果您嘗試在任何其他項目/情境/上下文中使用您的模型,可能會中斷。

+0

我想到的可能是1A的東西,也許是因爲它的簡單性。 – Jaryl 2008-09-25 15:29:23

1

你是對的,它打破了MVC。我建議在你的控制器中使用回調函數,主要是因爲有些情況(比如一個保存被調用但驗證失敗的模型),你不希望觀察者記錄任何東西。

6

這是一個棘手的情況。你幾乎要違反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是一個適當的方法,並將它保存它在線程本地存儲數據

+2

嗨,獵戶座,剛剛找到這個,因爲我正在尋找這種類型的解決方案。既然已經過了幾年了!你仍然使用這個解決方案嗎?好奇如果你碰到任何Threaded類型的問題? – WozPoz 2010-10-01 03:12:40

+1

@WozPoz此代碼不是線程安全的,在同一進程中運行的線程將共享類變量。要繞過這個障礙,可以使用線程本地存儲或者使用config.threadsafe運行你的應用程序! = false – laurie 2014-08-04 09:43:07

0

在過去,當做這樣的事情時,我傾向於擴展用戶模型類以包含'當前用戶'的想法

看看以前的答案,我看到建議來存儲實際活動記錄用戶在會話中。這有幾個缺點。

  • 它存儲在會話數據庫
  • 一個可能的大對象這意味着用戶的副本「緩存」的所有時間(或直到註銷被強制)。這意味着在用戶註銷並重新登錄之前,用戶狀態的任何更改都不會被識別。例如,這意味着嘗試禁用用戶將等待他註銷並重新登錄。這可能不是你想要的行爲。

因此,在請求開始時(在過濾器中),您從會話獲取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 

從那時起,它應該是微不足道的。

相關問題