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

我正在尝试测试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_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 是“线程安全的”,如果你在两个单独的线程中运行你的应用程序会发生什么?一位用户将登录,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

哦,顺便说一句,现在我再次查看您的问题,也许它不起作用的原因之一是该行将User.current_user && User.current_user.id返回一个布尔值,而不是您想要的整数。 编辑我是个白痴。

命名范围确实是绝对错误的做法。命名范围旨在返回集合,而不是单个记录(这是失败的另一个原因)。它还会对数据库进行不必要的调用,从而导致您不需要的查询。

于 2009-01-22T00:24:08.010 回答
0

我才意识到答案正盯着我看。我应该从协会的另一端工作,这将是current_user.batch_records。然后我只是named_scopeUser模型上测试一下,一切都很好。

@ Chris Lloyd - 关于线程安全问题,该current_user属性由before_filtermy中的 a 设置ApplicationController,因此根据请求进行修改。我知道如果我选择在多线程环境中运行(目前不是这种情况),仍然有可能发生灾难。我认为该解决方案将完全是另一个主题。

于 2009-01-22T01:04:36.883 回答