7

Ruby on Rails アプリケーションでユーザーのアクションをログに記録したいと考えています。

これまでのところ、更新および作成後にデータベースにログを挿入するモデル オブザーバーがあります。ログに記録されたアクションを実行したユーザーを保存するために、セッションへのアクセスが必要ですが、それは問題です。

まず、MVC モデルを壊します。第 2 に、ハック的なものから風変わりなものまでさまざまな手法があり、実装を Mongrel サーバーに結び付けることさえあるかもしれません。

取るべき正しいアプローチは何ですか?

4

6 に答える 6

6

うーん、これは厄介な状況です。MVCをうまく機能させるには、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

少しハックですが、私が見た他の多くのコアレールのものよりハックではありません。

スレッドセーフにするために必要なことは、cattr_accessor を適切なメソッドに変更し、そのデータをスレッド ローカル ストレージに格納することだけです (これはとにかく jruby で実行する場合にのみ重要です)。

于 2008-09-25T21:46:55.397 に答える
3

これは非常に興味深い質問だと思います。ここでちょっと大声で考えてみます…

最終的に直面するのは、特定の機能セットを実現するために、デザイン パターンの許容されるプラクティスに違反するという決定です。だから、私たちは自問しなければなりません

1)MVCパターンに違反しない可能性のある解決策は何ですか

2) MVC パターン違反する可能性のある解決策は何ですか?

3) どのオプションが最適ですか? 私はデザイン パターンと標準的な慣行を非常に重要だと考えていますが、同時に、それらに固執するとコードがより複雑になる場合は、慣習に違反することが適切な解決策になる可能性があります。それについて私に同意しない人もいるかもしれません。

最初に #1 について考えてみましょう。

頭のてっぺんから、次の可能な解決策を考えます

A) 誰がこれらのアクションを実行しているかに本当に関心がある場合、このデータを何らかの方法でモデルに保存する必要がありますか? この情報をオブザーバーが利用できるようにします。また、ActiveRecord クラスの他のフロントエンド呼び出し元が同じ機能を取得することも意味します。

B) 誰がエントリを作成したかを理解することにはあまり関心がないが、Web アクション自体をログに記録することに関心がある場合は、コントローラのアクションを「観察」することを検討してください。Railsソースを調べてからしばらく時間が経ったので、ActiveRecord::Observerがモデルを「観察」しているのかどうかはわかりませんが、コントローラーオブザーバーに適応させることができるかもしれません. この意味で、あなたはもはやモデルを監視していないので、そのオブザーバーにセッションやその他のコントローラー タイプのデータ情報を提供することは理にかなっています。C) 最小の「構造」を使用した最も簡単な解決策は、監視しているアクション メソッドの最後にロギング コードをドロップすることです。

ここでオプション #2 を検討して、MVC の慣行を破ります。

A)あなたが提案したように、モデルのオブザーバーにセッションデータへのアクセスを許可する手段を見つけることができます。モデルをビジネス ロジックに結合しました。

B)ここでは他に考えられません:)

私の個人的な傾向は、あなたのプロジェクトの詳細を知らなくても、人をレコードに関連付けたい場合は 1A、またはこれを行うことに関心のある場所がほんの少ししかない場合は 1C です。すべてのコントローラーとアクションに対して堅牢なログ ソリューションが本当に必要な場合は、1B を検討してください。

モデルオブザーバーにセッションデータを見つけさせるのは少し「臭い」ので、他のプロジェクト/状況/コンテキストでモデルを使用しようとすると壊れる可能性があります。

于 2008-09-25T15:09:13.277 に答える
1

私が選んだ答えによって示唆されていることを行うためのきれいな方法を見つけました。

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

このソリューションは、AuditLog モデルと TrackChanges モジュールを使用して、追跡機能を任意のモデルに追加します。ただし、更新または作成するときに、コントローラーに行を追加する必要があります。

于 2009-03-26T04:53:21.657 に答える
1

あなたはMVCを壊すことについて正しいです。コントローラーでコールバックを使用することをお勧めします。これは主に、オブザーバーが何もログに記録したくない状況 (save が呼び出されたが検証に失敗したモデルなど) があるためです。

于 2008-09-25T15:00:07.073 に答える
0

In the past, when doing something like this, I have tended towards extending the User model class to include the idea of the 'current user'

Looking at the previous answers, I see suggestions to store the actual active record user in the session. This has several disadvantages.

  • It stores a possibly large object in the session database
  • It means that the copy of the user is 'cached' for all time (or until logout is forced). This means that any changes in status of this user will not be recognised until the user logs out and logs back in. This means for instance, that attempting to disable the user will await him logging off and back on. This is probably not the behaviour you want.

So that at the beginning of a request (in a filter) you take the user_id from the session and read the user, setting User.current_user.

Something like this...

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

From then on it should be trivial.

于 2008-10-03T10:04:43.063 に答える
0

http://www.zorched.net/2007/05/29/making-session-data-available-to-models-in-ruby-on-rails

于 2012-02-28T13:22:22.290 に答える