Pergunta

Eu quero log ações do usuário no meu aplicativo Ruby on Rails.

Até agora, eu tenho um modelo observador que insere registros no banco de dados após atualizações e cria. Para armazenar o usuário que executou a ação que foi registrada, eu exigem acesso à sessão, mas isso é problemático.

Em primeiro lugar, ele quebra o modelo MVC. Em segundo lugar, as técnicas vão desde a hackish ao estranho, talvez até mesmo amarrar a implementação para o servidor Mongrel.

O que é o caminho certo a tomar?

Foi útil?

Solução

Eu acho que isso seja uma questão muito interessante. Vou pensar em voz alta aqui um momento ...

Em última análise, o que estamos confrontados com uma decisão de violar uma prática de design de padrão aceitável para atingir um conjunto específico de funcionalidade. Então, devemos nos perguntar

1) Quais são as soluções possíveis que não violam padrão MVC

2) Quais são as soluções possíveis que faria violar o padrão MVC

3) qual a melhor opção? Considero padrões de projeto e práticas padrão muito importantes, mas, ao mesmo tempo, se segurando para eles torna seu código mais complexo, então a solução certa pode muito bem ser a violar a prática. Algumas pessoas podem discordar de mim sobre isso.

Vamos considerar # 1 em primeiro lugar.

Em cima da minha cabeça, eu acho que uma das seguintes soluções possíveis

A) Se você está realmente interessado em que está realizando essas ações, devem esses dados ser armazenados no modelo de alguma forma? Seria tornar essa informação disponível para o seu Observer. E isso também significa que qualquer outro chamador front-end de sua classe ActiveRecord recebe a mesma funcionalidade.

B) Se você não está realmente interessado em compreender que criou uma entrada, mas mais interessado em registrando-se as ações da web, então você pode considerar "observar" as ações do controlador. Já faz algum tempo desde que eu remexia fonte do Rails, então eu não tenho certeza de que sua ActiveRecord :: Observer "observa" o modelo, mas você pode ser capaz de adaptá-lo a um observador controlador. Neste sentido, você não está observando o modelo mais, e faz sentido fazer sessão e outras informações de dados tipo de controlador para esse observador. C) A solução mais simples, com o mínimo de "estrutura", é simplesmente soltar o seu código de registro no final de seus métodos de ação que você está assistindo.

Considere a opção # 2 agora, quebrando práticas MVC.

A) Como você propõe, você poderia encontrar os meios para obter a sua Observer modelo a ter acesso aos dados de sessão. Você acoplada seu modelo para sua lógica de negócios.

B) Não consigo pensar em quaisquer outros aqui:)

A minha inclinação pessoal, sem saber mais detalhes sobre seu projeto, ou é 1A, se eu quiser anexar as pessoas com registros, ou 1C, se há apenas alguns lugares onde eu estou interessado em fazer isso. Se você está realmente querendo uma solução de registro robusto para todos os seus controladores e ações, você pode considerar 1B.

Tendo seus dados de sessão modelo observador encontrar é um pouco "fedido", e provavelmente iria quebrar se você tentou usar o seu modelo em qualquer projeto other / situação / contexto.

Outras dicas

Hrm, esta é uma situação complicada. Você praticamente tem que violar MVC para fazê-lo funcionar bem.

Eu faria algo assim:

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

É um pouco hacky, mas não é mais hacky do que muitos outros núcleo trilhos coisas que eu vi.

Tudo o que você precisa fazer para torná-lo threadsafe (isso só importa se você rodar em JRuby de qualquer maneira) é mudar o cattr_accessor ser um método adequado, e tê-lo armazenar os dados no segmento local de armazenamento

Você está certo sobre isso quebrar MVC. Gostaria de sugerir o uso de chamadas de retorno em seus controladores, principalmente porque há situações (como um modelo que salvar é chamado, mas falha de validação), onde você não iria querer uma coisa logging observador.

Eu encontrei uma maneira limpa para fazer o que é sugerido pela resposta que eu escolhi.

http://pjkh.com / artigos / 2009/02/02 / criar-um-audit-log-in-rails

Esta solução usa um modelo AuditLog, bem como um TrackChanges módulo para adicionar rastreamento funcionalidade para qualquer modelo. Ele ainda requer que você adicione uma linha ao controlador quando você atualizar ou criar embora.

No passado, ao fazer algo como isso, eu tendia para estender a classe modelo User para incluir a idéia do 'usuário atual'

Olhando para as respostas anteriores, vejo sugestões para armazenar o usuário registro ativo real na sessão. Isto tem várias desvantagens.

  • Ele armazena um possível objeto grande no banco de dados sessão
  • Isso significa que a cópia do usuário é 'cache' de todos os tempos (ou até de logout é forçado). Isto significa que quaisquer mudanças no status deste usuário não será reconhecido até que o usuário fizer fora e registra novamente. Isso significa, por exemplo, que a tentativa de desativar o usuário vai aguardar o log off e volta. Isto provavelmente não é o comportamento desejado.

De modo que, no início de um pedido (em um filtro) você tomar o user_id da sessão e ler o usuário, definindo User.current_user.

Algo assim ...

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 então deveria ser trivial.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top