【问题标题】:Chaining ActiveRecord scopes leads to undefined method for []:Array链接 ActiveRecord 范围会导致 []:Array 的未定义方法
【发布时间】:2014-07-21 14:05:17
【问题描述】:

我仅在使用 RSpec 的测试环境中遇到此错误。该代码适用于所有其他环境,包括 Rails 控制台。

鉴于此代码

class User < ActiveRecord::Base
  scope :flag, -> {where(flag: nil) } 
end

当我打电话给User.where(expired_at: nil).flag

然后结果是undefined methodflagfor []:Array

我正在使用 Rails 4.1.1 和 rspec-rails 2.14.0。

【问题讨论】:

  • 你的User.where方法被覆盖了吗?
  • 不,我没有覆盖 User.where 方法。
  • 当然User类继承ActiveRecord::Base之后?
  • 好吧,这很奇怪。 User.method(:where).source_location 返回什么?
  • /.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rspec-mocks-2.14.6/lib/rspec/mocks/method_double.rb 这对我有帮助很多东西要找到答案:在我的 RSpec 示例中,我执行 User.stub(:where).and_return([])。

标签: ruby-on-rails activerecord rspec rspec2 ruby-on-rails-4.1


【解决方案1】:

使用该存根,您的“User.where(expired_at: nil)”将返回 [],您的代码将使用它,然后尝试在其上调用“flag”。由于 Ruby 中的数组没有名为“flag”的方法,因此您看到的异常会被抛出。有几种方法可以处理这个问题。

1) 不要存根该调用。只需让框架处理它(是的,它会尝试访问数据库,这可能是您在这里试图避免的,但仍然是一种选择)。

2) 返回一个测试双精度而不是一个空数组,如

results = double(:expired_users, flag: [])
User.stub(:where).and_return(expired_users)

看看 flag 是如何在 ":expired_users" 上存根的以返回一个空数组?

3) 向您的用户模型添加一个方法,该方法基本上运行您想要的并将其存根,例如:

class User
  def self.flagged_expired_users
    where(expired_at: nil).flag
  end
end

在规范中

User.stub(:flagged_expired_users).and_return([])

我自己更喜欢#3,因为根据我的经验,这种测试/模拟风格往往不那么脆弱,但是 ymmv。

【讨论】:

    【解决方案2】:

    在我的 RSpec 示例中,我调用 User.stub(:where).and_return([])

    我把它换成了User.stub(:where).and_return(User.all)

    【讨论】:

    • 如果你只是想让存根返回 User.all,它会访问数据库,只需完全删除这个存根。如果您希望它返回一些数据,请创建符合条件的用户记录(已过期和标记)。
    猜你喜欢
    • 2011-11-09
    • 2012-10-20
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-06-10
    • 2014-05-29
    • 2012-05-11
    • 1970-01-01
    相关资源
    最近更新 更多