Хорошая идея, чтобы получить доступ к сессии в обозревателе или нет? - PullRequest
7 голосов
/ 25 сентября 2008

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

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

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

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

Ответы [ 6 ]

6 голосов
/ 26 сентября 2008

Хм, это неприятная ситуация. Вы в значительной степени ДОЛЖНЫ нарушать 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 на правильный метод и хранить данные в локальном потоке

3 голосов
/ 25 сентября 2008

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

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

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

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

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

Давайте сначала рассмотрим # 1.

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

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

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

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

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

Б) Не могу думать о других здесь:)

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

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

1 голос
/ 26 марта 2009

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

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

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

1 голос
/ 25 сентября 2008

Вы правы в том, что нарушаете MVC. Я бы предложил использовать обратные вызовы в ваших контроллерах, в основном потому, что существуют ситуации (например, вызывается сохранение, но проверка не проходит), когда вы не хотите, чтобы наблюдатель что-либо регистрировал.

0 голосов
/ 28 февраля 2012
0 голосов
/ 03 октября 2008

В прошлом, когда я делал что-то подобное, я стремился расширить класс модели 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

С этого момента это должно быть тривиально.

...