2016-11-10 73 views
3

我有下一个问题。当我尝试删除ActiveRecord模型的实例方法allow_any_instance_of我收到错误消息“模型没有实现#method”,但如果我发送真正的请求数据库创建或选择此模型的实例对象之前,此存根(stub)我没有这个信息,一切都很好! 我在控制台同样的问题Rails Rspec allow_any_instance_of为ActiveRecord对象属性引发“不执行”错误

Reloading... 

>> Search.method_defined?(:tickets_count) 
=> false 

>> Search.method_defined?(:affiliate_id) 
=> false 

>> Search.last 
    Search Load (3.9ms) SELECT "searches".* FROM "searches" ORDER BY "searches"."id" DESC LIMIT 1 
=> #<Search:0x007fe2aecf2900 
id: 515711, 
tickets_count: 1, 
affiliate_id: nil 

>> Search.method_defined?(:affiliate_id) 
=> true 

>> Search.method_defined?(:tickets_count) 
=> true 

可能有人解释,这到底是怎么回事吗?))

回答

4

什么你正在运行到这里是数据库的懒惰实例属性访问器方法由activerecord。

TL; DR可以使用这样的事情https://github.com/rspec/rspec-rails/issues/1357

本质的ActiveRecord :: Base的类不定义任何数据库,基于列的制定者/吸气,直到他们需要,通常通过一种方法缺失钩,尽管可能有其他事情可能导致它们被定义,例如调用Search.find_by_affiliate_id也可能导致定义加载。

我可以提供关于它如何工作的一种高级解释,但可能有更好/更新的资源可以更好地解释它,或者您可以通过ActiveRecord源代码这虽然有点迟钝,但对于理解其行为可能是一个合理的选择。

那么为什么不定义这些方法呢?

当从ActiveRecord::Base继承创建一个新的ActiveRecord类时,所有类都知道它是预期的表名,但是不知道并且无法知道该表没有连接到数据库的哪些列。不知道哪些列存在,它不知道要定义哪些读者/作者。 ActiveRecord不会在加载时主动查询数据库,我认为这是一件非常好的事情,因为它可以让您在不需要迁移的连接数据库的情况下加载代码。

ActiveRecord的确实是什么钩住method_missingresponds_to?等,以确定何时被调用在未限定的ActiveRecord类的方法,试图加载当前分贝模式和其自身上限定读/写器/存取方法对于找到的每个列,然后重试该方法调用以查看它是否已被定义。

在你上面的例子,很可能.last调用,它定义的属性,而是你的终端以打印Search对象的实例运行.inspect电话。

要测试这个,你可以重新运行上面的例子,但用(s = Search.last).nil?代替Search.last。如果你这样做,我会打赌Search.method_defined?(:affiliate_id)仍然是错误的。

希望能够解释为什么这些方法一开始就没有定义,但后来才被定义。这也是您无法使用alias_method :aliased_affiliate_id, :affiliate_id的原因,因为在加载时没有定义方法affiliat_id,所以会失败。

对于你想要做的事情,你需要决定是否值得它需要一个活动的数据库连接来运行这些规范。

如果是这样,您可以触发您的ActiveRecord类来加载它们的表定义,并在您的规格中定义它们的读写器属性以便通过。

这里的人运行到同样的问题与加载定义ActiveRecord的类猴子补丁解决方案的RSpec:

https://github.com/rspec/rspec-rails/issues/1357

相关问题