Pregunta

Deseo registrar las acciones del usuario en mi aplicación Ruby on Rails.

Hasta ahora, tengo un observador modelo que inserta registros en la base de datos después de las actualizaciones y crea. Para almacenar qué usuario realizó la acción que se registró, requiero acceso a la sesión, pero eso es problemático.

En primer lugar, rompe el modelo MVC. En segundo lugar, las técnicas van desde lo intrincado a lo extravagante, tal vez incluso vinculando la implementación al servidor Mongrel.

¿Cuál es el enfoque correcto para tomar?

¿Fue útil?

Solución

Me parece una pregunta muy interesante. Voy a pensar en voz alta aquí un momento ...

En última instancia, nos enfrentamos a una decisión de violar una práctica aceptable de patrón de diseño para lograr un conjunto específico de funcionalidad. Entonces, debemos preguntarnos

1) ¿Cuáles son las posibles soluciones que no violan el patrón MVC

2) ¿Cuáles son las posibles soluciones que podrían infringir el patrón MVC

3) ¿Qué opción es la mejor? Considero que los patrones de diseño y las prácticas estándar son muy importantes, pero al mismo tiempo si mantenerlos hace que su código sea más complejo, entonces la solución correcta podría ser violar la práctica. Algunas personas pueden estar en desacuerdo conmigo en eso.

Consideremos primero el número 1.

Desde lo alto de mi cabeza, pensaría en las siguientes soluciones posibles

A) Si está realmente interesado en quién está realizando estas acciones, ¿deberían estos datos almacenarse en el modelo de alguna manera? Pondría esta información a disposición de su observador. Y también significa que cualquier otro interlocutor de su clase ActiveRecord obtiene la misma funcionalidad.

B) Si no está realmente interesado en comprender quién creó una entrada, pero está más interesado en registrar las acciones de la web, entonces podría considerar "observar". Las acciones del controlador. Ha pasado algún tiempo desde que examiné la fuente de Rails, así que no estoy seguro de quién es su ActiveRecord :: Observer " observa " el modelo, pero es posible que pueda adaptarlo a un observador controlador. En este sentido, ya no está observando el modelo, y tiene sentido hacer que la información de datos de sesión y otro tipo de controlador para ese observador. C) La solución más simple, con la menor "estructura", es simplemente soltar el código de registro al final de los métodos de acción que estás viendo.

Considere la opción # 2 ahora, rompiendo las prácticas MVC.

A) Como propone, podría encontrar los medios para que su Observador modelo tenga acceso a los datos de la Sesión. Ha acoplado su modelo a su lógica empresarial.

B) No puedo pensar en ningún otro aquí :)

Mi inclinación personal, sin conocer más detalles sobre su proyecto, es 1A, si quiero adjuntar personas a los registros, o 1C si solo hay unos pocos lugares en los que estoy interesado en hacer esto. Si realmente desea una solución de registro sólida para todos sus controladores y acciones, puede considerar 1B.

Hacer que el observador de su modelo encuentre datos de sesión es un poco `` apestoso '' y probablemente se rompería si intentara usar su modelo en cualquier otro proyecto / situación / contexto.

Otros consejos

Hrm, esta es una situación difícil. Tiene que violar MVC para que funcione bien.

Haría algo como esto:

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

Es un poco intrincado, pero no es más intrépido que muchas otras cosas principales que he visto.

Todo lo que deberías hacer para que sea seguro para subprocesos (esto solo importa si ejecutas en jruby de todos modos) es cambiar el cattr_accessor para que sea un método adecuado, y hacer que almacene sus datos en el almacenamiento local de subprocesos

Tienes razón al romper MVC. Yo sugeriría usar devoluciones de llamada en sus controladores, principalmente porque hay situaciones (como un modelo al que se llama guardar pero falla la validación) donde no querría que un observador registre nada.

Encontré una manera limpia de hacer lo que sugiere la respuesta que elegí.

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

Esta solución utiliza un modelo AuditLog así como un módulo TrackChanges para agregar funcionalidad de seguimiento a cualquier modelo. Todavía requiere que agregue una línea al controlador cuando actualice o cree.

En el pasado, al hacer algo como esto, he tendido a extender la clase de modelo de Usuario para incluir la idea del 'usuario actual'

En cuanto a las respuestas anteriores, veo sugerencias para almacenar el usuario del registro activo real en la sesión. Esto tiene varias desventajas.

  • Almacena un objeto posiblemente grande en la base de datos de la sesión
  • Significa que la copia del usuario está 'almacenada en caché' todo el tiempo (o hasta que el cierre de sesión sea forzado). Esto significa que cualquier cambio en el estado de este usuario no se reconocerá hasta que el usuario cierre la sesión y vuelva a iniciarla. Esto significa, por ejemplo, que intentar deshabilitar al usuario esperará que cierre la sesión y vuelva a iniciarla. Probablemente este no sea el comportamiento que desea.

Para que al comienzo de una solicitud (en un filtro) tome el user_id de la sesión y lea al usuario, configurando User.current_user.

Algo así ...

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

A partir de entonces debería ser trivial.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top