2008-09-25 7 views
7

Ruby on Rails 응용 프로그램에서 사용자의 동작을 기록하고 싶습니다.옵서버에서 세션에 액세스하는 것이 좋습니까?

지금까지 필자는 업데이트 후 생성 된 로그를 데이터베이스에 삽입하고 생성하는 모델 관찰자가 있습니다. 어떤 사용자가 기록 된 작업을 수행했는지 저장하려면 세션에 대한 액세스가 필요하지만 문제가 있습니다.

먼저 MVC 모델을 중단합니다. 둘째, 기술은 hackish에서 이방인에 이르기까지 다양하며 구현을 Mongrel 서버에 묶는 것조차도 있습니다.

올바른 방법은 무엇입니까?

답변

3

매우 흥미로운 질문입니다. 여기에 잠시 큰 소리로 생각할 것입니다 ...

궁극적으로, 우리가 직면 한 것은 특정 기능 세트를 달성하기 위해 디자인 패턴 허용 가능한 방법을 위반하는 결정입니다. 그래서 우리는 우리 자신을 요청해야합니다

하지는 MVC 패턴

3을 위반하는 것이 가능한 해결책은 무엇 MVC 패턴

2) 위반 가능한 솔루션은 무엇

1)) 어떤 옵션이 가장 좋습니까? 나는 디자인 패턴과 표준 관행을 매우 중요하게 생각하지만, 동시에 코드를 붙이면 코드가 더욱 복잡해진다. 올바른 해결책은 관행을 위반하는 것일 수있다. 어떤 사람들은 저와 동의하지 않을 수도 있습니다.

먼저 # 1을 고려하십시오.

내 머리 위로 떨어져

, 난 당신이 데이터가 어떤 식 으로든 모델에 보관해야합니다 이러한 작업을 수행하는 사람에 정말 관심이 있다면 다음과 같은 가능한 솔루션

A)의 생각? 옵서버가이 정보를 사용할 수 있도록합니다. 또한 ActiveRecord 클래스의 다른 프런트 엔드 호출자도 동일한 기능을 사용함을 의미합니다.

B) 항목을 만든 사람을 이해하는 데 정말로 관심이 없지만 웹 작업 자체를 로깅하는 것이 더 흥미로운 경우 컨트롤러 동작을 "관찰"하는 것이 좋습니다. Rails 소스를 훑어 본 이래로 얼마간의 시간이 걸렸으므로 ActiveRecord :: Observer가 모델을 "관찰"하는 사람이 누구인지 모르겠지만 컨트롤러 관찰자에게이를 적용 할 수는 있습니다. 이러한 의미에서 더 이상 모델을 관찰하지 않고 세션 및 다른 컨트롤러 유형 데이터 정보를 해당 관찰자에게 제공하는 것이 합리적입니다. C) "구조"가 가장 적은 가장 간단한 솔루션은보고있는 동작 메서드의 끝 부분에 로깅 코드를 놓기 만하면됩니다.

이제 MVC 사례를 깨고 옵션 # 2를 고려하십시오.

A) 제안한대로 Observer 모델을 세션 데이터에 액세스 할 수있는 방법을 찾을 수 있습니다. 비즈니스 논리에 모델을 결합했습니다.

B)는 귀하의 프로젝트에 대해 더 이상 자세한 내용을 모른 채 여기 어떤 다른 사람 :

내 개인적인 성향, 생각하지 수, 다음 중 하나입니다 1A, 나는이있는 경우 기록에 사람, 또는 1C을 연결하려는 경우 내가이 일에 관심이있는 곳이 몇 군데 밖에 없다. 모든 컨트롤러와 작업에 대한 강력한 로깅 솔루션을 원한다면 1B를 고려해보십시오.

모델 관찰자가 세션 데이터를 찾게하는 것이 조금 "냄새 나는"일이며, 다른 프로젝트/상황/상황에서 모델을 사용하려고 시도하면 문제가 발생할 수 있습니다.

+0

나는 단순함 때문에 아마 1A와 같은 것을 생각하고있었습니다. – Jaryl

1

MVC를 위반하는 것이 맞습니다. 컨트롤러에서 콜백을 사용하는 것이 좋습니다. 왜냐하면 관찰자가 아무것도 로깅하지 않기를 바라는 상황이 있기 때문입니다.

6

Hrm, 이는 끈적한 상황입니다. 당신은 꽤 잘 작동하도록 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 

그것은 조금 해키,하지만 다른 많은 코어가 내가 본 일을 레일 것보다 더 이상 해키 없습니다.

당신이 (당신이 어쨌든 JRuby를 실행하는 경우이 문제 만)이 스레드를 만들기 위해해야 ​​할 것입니다 모든 적절한 방법이 될하기 위해 cattr_accessor을 변경하고 스레드 로컬 스토리지에서 데이터의 IT 저장하는 것입니다

+2

안녕하세요 오리온,이 솔루션 유형을 찾고 있습니다. 몇 년이 지났기 때문에! 이 솔루션을 계속 사용합니까? 당신이 Threaded 타입의 문제에 부딪쳤다면 궁금할까요? – WozPoz

+1

@WozPoz이 코드는 스레드로부터 안전하지는 않습니다. 동일한 프로세스에서 실행되는 스레드는 클래스 변수를 공유합니다. 이 장애물을 해결하려면 스레드 로컬 저장소를 사용하거나 config.threadsafe로 응용 프로그램을 실행하십시오! = false – laurie

0

과거에 이와 같은 일을 할 때 '현재 사용자'아이디어를 포함하도록 User 모델 클래스를 확장하는 경향이있었습니다.

이전 답변을 보면 실제 활성 레코드를 저장하기위한 제안 사항이 있습니다 세션의 사용자. 여기에는 몇 가지 단점이 있습니다.

  • 그것은 그것은 사용자의 사본이 모든 시간을 '캐시'(또는 로그 아웃이 강제 될 때까지)을 의미 세션 데이터베이스
  • 의 가능성이 큰 객체를 저장합니다. 즉, 사용자가 로그 아웃하고 다시 로그인 할 때까지는이 사용자 상태의 모든 변경 사항이 인식되지 않습니다. 즉, 사용자를 비활성화하려고 시도하면 해당 사용자가 로그 오프하고 다시 로그온 할 수 있습니다. 이것은 아마도 당신이 원하는 행동이 아닙니다.

필터의 요청 시작시 세션에서 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 

는 사소한해야한다.

+0

응용 프로그램 클래스 란 무엇입니까? – WozPoz

+0

컨트롤러라고 말하고 싶습니다. –

1

제가 선택한 대답에 의해 제안 된 것을 수행하는 깨끗한 방법을 발견했습니다.

http://pjkh.com/articles/2009/02/02/creating-an-audit-log-in-rails

이 솔루션은 어떤 모델에 추적 기능을 추가 할 AuditLog 보고서 모델뿐만 아니라 TrackChanges 모듈을 사용합니다. 업데이트하거나 만들 때 컨트롤러에 줄을 추가해야합니다.

관련 문제