0

次の ActiveRecord クラスがあります。

class User < ActiveRecord::Base
  cattr_accessor :current_user
  has_many :batch_records
end

class BatchRecord < ActiveRecord::Base
  belongs_to :user

  named_scope :current_user, lambda {
    { :conditions => { :user_id => User.current_user && User.current_user.id } }
  }
end

私はShouldanamed_scope :current_userを使ってテストしようとしていますが、以下はうまくいきません。

class BatchRecordTest < ActiveSupport::TestCase
  setup do
    User.current_user = Factory(:user)
  end

  should_have_named_scope :current_user,
                          :conditions => { :assigned_to_id => User.current_user }
end

それが機能しない理由は、クラスが定義されているときにメソッドUser.current_user内の呼び出しが評価されており、テストの実行時にブロック内の値を後で変更しているためです。should_have_named_scopecurrent_usersetup

このnamed_scopeをテストするために私が思いついたのは次のとおりです。

class BatchRecordTest < ActiveSupport::TestCase
  context "with User.current_user set" do
    setup do
      mock_user = flexmock('user', :id => 1)
      flexmock(User).should_receive(:current_user).and_return(mock_user)
    end

    should_have_named_scope :current_user,
                            :conditions => { :assigned_to_id => 1 }
  end
end

では、これをShouldaを使用してどのようにテストしますか?

4

2 に答える 2

1

あなたはこれについて間違った方法で進んでいると思います。まず、名前付きスコープを使用する必要があるのはなぜですか? これだけではいけませんか?

class BatchRecord < ActiveRecord::Base
  belongs_to :user

  def current_user
    self.user.class.current_user
  end
end

その場合、テストするのは簡単です。しかし!WTF をcurrent_userクラス属性として定義していますか? Rails 2.2 は「スレッドセーフ」になったので、アプリを 2 つの別々のスレッドで実行するとどうなるでしょうか? 1 人のユーザーがログインし、current_userすべてのUserインスタンスに を設定します。ここで、管理者権限を持つ別のユーザーがログインしcurrent_user、インスタンスに切り替えられます。最初のユーザーが次のページに移動すると、管理者権限で他のユーザーのアカウントにアクセスできます。ショック!ホラー!

current_userこの場合、現在のユーザーの User インスタンスを返す新しいコントローラー メソッドを作成することをお勧めします。さらに一歩進んで、次のようなラッパー モデルを作成することもできます。

class CurrentUser

  attr_reader :user, :session

  def initialize(user, session)
    @user, @session = user, session
  end

  def authenticated?
    ...
  end

  def method_missing(*args)
    user.send(*args) if authenticated?
  end

end

ああ、ところで、あなたの質問をもう一度見てみましょう。おそらく、それが機能しない理由の 1 つは、User.current_user && User.current_user.id必要な整数ではなく、行がブール値を返すことです。 編集私はばかです。

名前付きスコープは、これを行う絶対に間違った方法です。名前付きスコープは、個々のレコードではなくコレクションを返すことを目的としています (これが失敗するもう 1 つの理由です)。また、DB を不必要に呼び出して、不要なクエリを実行しています。

于 2009-01-22T00:24:08.010 に答える
0

答えが私を見つめていることに気づきました。私は協会の反対側から働いているはずですcurrent_user.batch_recordsnamed_scope次に、Userモデルで をテストするだけで、すべて問題ありません。

@ Chris Lloyd - スレッド セーフの問題に関して、current_user属性はbefore_filtermyApplicationControllerで a によって設定されているため、リクエストごとに変更されます。マルチスレッド環境で実行することを選択した場合、災害の可能性がまだあることを理解しています (現在はそうではありません)。その解決策は、まったく別のトピックになると思います。

于 2009-01-22T01:04:36.883 に答える