2009-07-06 10 views
2

私のレールアプリでは、モデルの変更者を追跡し、モデルのテーブルのフィールドを更新して反映させたいと思います。Railsのモデル変更を自動的に追跡する

だから、例えば私たちは持っている:

class Foo < ActiveRecord::Base 
    before_create :set_creator 
    belongs_to :creator, :class_name => "User" 

    protected 

    def set_creator 
    # no access to session[:user_id] here... 
    end 
end 

私のモデルからのuser_idで取得するための良いテスト可能な方法は何ですか?私はThread.currentでこのデータを乱用すべきですか?

コントローラからこの情報を渡す方が良いでしょうか?

答えて

2

ベストプラクティスは、あなたのモデルはステートレスで持つことである、コントローラは状態を扱うようになりました。情報をモデルに取り入れる場合は、コントローラから渡す必要があります。ステートフルなデータを追加しようとしているので、ここで作成フックを使うのは正しい方法ではありません。これらのフックは実際にはステートレスな動作のためのものです。

あなたは、コントローラからで情報渡すことができます。あなた自身が権限コードをたくさん書い見つけた場合

class User 
    def create_foo(params) 
    Foo.new(params.merge! {:creator_id => self.id}) 
    end 
end 

Foo.new(params[:foo].merge {:creator_id => current_user.id}) 

それとも、これらの操作を処理するために、ユーザーのメソッドを作成することができますがコントローラーでは、オプション2を使用します。これは、そのコードをモデルにリファクタリングすることができるからです。それ以外の場合、オプション1はよりクリーンです。

オマールは、自動化するのがやりにくいと指摘していますが、それでもやり遂げることはできます。ここでは、ユーザーにcreate_somethingインスタンスメソッドを使用して、一つの方法です:あなたはまた、施工上のuser_idsを必要とする、または新しいラップApplicationControllerに内部メソッドを作成するためのコンストラクタをオーバーライドすることができます

def method_missing(method_sym, *arguments, &block) 
    meth = method_sym.to_s 
    if meth[0..6] == "create_" 
     obj = meth[7..-1].classify.constantize.new(*arguments) 
     obj.creator_id = self.id 
    else 
    super 
    end 
end 

多分もっと上品なやり方がありますが、モデルコードの中から状態を読み取ろうとするのは間違いです。MVCのカプセル化が壊れてしまいます。私は明示的に、それを別の方法で渡すことを大いに好みます。

+0

あなたは何を知っていますか、私はこれに向かって傾いていますが、副作用の解決策はちょっと...ああ... ...好きには効果的です。 –

+0

スレッドセーフですか?はい。自動化された?そうではありません。問題は、すべてのモデルをcreator_id列で追跡する必要があることです。 updater_id列を追加したい場合はどうなりますか?ロジックをさらに管理する必要があります。また、私は場合によってはcreator_id属性をマージする必要があることを忘れてしまうでしょう。私の好きなことを追跡することが多すぎます。 –

+0

いくつかの自動化機能を追加しましたが、これに対するより良い解決策の余地は間違いありません。 –

0

私はuser_idを呼び出すすべてのもの(主にコントローラ)から新しいsave、updateなどのメソッドを作成したいと思います。

私はおそらくActiveRecord:Baseを、この動作を必要とするすべてのモデルでこれを処理する新しいクラスに拡張します。

0

私はThread.currentを信頼しませんが、ちょっとハッキリしているようです。私はいつも引数を取るカスタムメソッドを呼び出します:

MVCパターンに従います。明らかに倫理的な問題は、どこでもcreate_with_creatorと呼ぶことになるということです。

0

PaperTrailが便利です。 (フィルタの前の内側

User.current_user = current_user 

+0

Thread.currentを実行するのを避けますが、グローバル変数と中央モジュールを使用して現在のユーザーを追跡します。 –

+0

Thread.currentを使用しています。 –

1

ええ、そのようなことは仕事、またはあなたがのようなものを持つことができ、あなたのコントローラに

cattr_accessor :current_user 

その後、あなたのUserモデルにクラス変数を持つでしょうcurrent_userがログインしているユーザーであると仮定します)。

次に、AR:Baseのcreate/updateメソッドを拡張して、モデル上にcreated_by/updated_byフィールドの存在をチェックし、値をUser.current_userに設定することができます。

+0

スレッドの安全性について気にしないかと思います。 –

関連する問題