質問

次の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

Shoulda を使用してnamed_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_scopeの呼び出しが評価され、その後current_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 を使用して、これをどのようにテストしますか?

役に立ちましたか?

解決

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

class BatchRecord < ActiveRecord::Base
  belongs_to :user

  def current_user
    self.user.class.current_user
  end
end

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

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

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

ああ、ところで、私はあなたの質問をもう一度見てみましょう。 編集私はバカです。

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

他のヒント

I just realized the answer is staring right at me. I should be working from the other side of the association which would be current_user.batch_records. Then I simply test the named_scope on the User model and everything is fine.

@Chris Lloyd - Regarding the thread safety issue, the current_user attribute is being set by a before_filter in my ApplicationController, so it is modified per request. I understand that there is still the potential for disaster if I chose to run in a multi-threaded environment (which is currently not the case). That solution I suppose would be another topic entirely.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top