2008-09-25 3 views
7

Я хочу регистрировать действия пользователя в моем приложении Ruby on Rails.Хорошая идея получить доступ к сеансу в наблюдателе или нет?

До сих пор у меня есть модель наблюдателя, который вставляет журналы в базу данных после обновлений и создает. Чтобы сохранить, какой пользователь выполнил действие, которое было зарегистрировано, мне нужен доступ к сеансу, но это проблематично.

Во-первых, он разрушает модель MVC. Во-вторых, методы варьируются от хакерских до диковинных, возможно, даже связывая реализацию с сервером Mongrel.

Каков правильный подход?

ответ

3

Я нахожу, что это очень интересный вопрос. Я собираюсь задуматься вслух здесь ...

В конечном итоге мы сталкиваемся с тем, что мы решили нарушить приемлемую практику шаблона проектирования, чтобы достичь определенного набора функций. Таким образом, мы должны спросить себя

1) Каковы возможные решения, которые бы не нарушившие MVC шаблон

2) Каковы возможные решения, которые бы нарушающим шаблон MVC

3) Какой вариант лучше? Я считаю, что шаблоны проектирования и стандартные методы очень важны, но в то же время, если удержание их делает ваш код более сложным, правильным решением может быть нарушение правил. Некоторые люди могут не согласиться со мной по этому поводу.

Давайте рассмотрим вопрос № 1.

Off верхней части моей головы, я бы думать о следующих возможных решений

A) Если вы действительно заинтересованы в том, кто выполняет эти действия, должны эти данные должны храниться в модели каким-либо образом? Это сделает эту информацию доступной для вашего наблюдателя. А это также означает, что любой другой пользовательский интерфейс вашего класса ActiveRecord получает одинаковые функции.

B) Если вам неинтересно понимать, кто создал запись, но больше заинтересованы в регистрации самих веб-действий, вы можете подумать о «наблюдении» действий контроллера. Прошло некоторое время с тех пор, как я попытался найти источник Rails, поэтому я не уверен, что их ActiveRecord :: Observer «наблюдает» за моделью, но вы можете адаптировать ее к наблюдателю контроллера. В этом смысле вы больше не наблюдаете модель, и имеет смысл сделать эту информацию о сеансе и другой информации типа контроллера этому наблюдателю. C) Самое простое решение с наименьшей «структурой» - это просто отказаться от кода регистрации в конце ваших методов действий, которые вы смотрите.

Рассмотрите вариант №2 сейчас, нарушая практику MVC.

A) Как вы предлагаете, вы могли бы найти средства, чтобы ваша модель Observer имела доступ к данным сеанса. Вы привязали свою модель к своей бизнес-логике.

B) Не может думать ни о каком других здесь :)

Моего личного наклонения, не зная больше подробностей о вашем проекте, либо 1A, если я хочу, чтобы прикрепить человек к записям, или 1С, если есть только в нескольких местах, где я заинтересован в этом. Если вы действительно хотите найти надежное решение для ведения журналов для всех своих контроллеров и действий, вы можете рассмотреть 1B.

Наличие вашей модели наблюдателя нахождение данных сеанса немного «вонючий» и, скорее всего, будет ломаться, если вы попытаетесь использовать вашу модель в любом другом проекте/ситуации/контексте.

+0

Я думал, может быть что-то вроде 1А, возможно, из-за своей простоты. – Jaryl 2008-09-25 15:29:23

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 

Это немного Hacky, но это не более чем Hacky многих других основных рельсам вещи, которые я видел.

Все, что вам будет нужно сделать, чтобы потоко (это только те вопросы, если вы бежите на 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 

С тех пор на нем должна быть тривиальной.

1

Я нашел чистый способ сделать то, что предлагает ответ, который я выбрал.

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

Это решение использует модель AuditLog, а также модуль TrackChanges для добавления функциональности отслеживания к любой модели. По-прежнему требуется добавить строку в контроллер при обновлении или создании.

Смежные вопросы