eug*_*bin 5 rspec ruby-on-rails stubbing rails-activerecord
我有下一个问题.当我尝试使用allow_any_instance_of来存储ActiveRecord模型的实例方法时,我收到错误消息"模型没有实现#method",但是如果我发送实际请求到数据库创建或选择此模型的实例对象之前,我不有这个消息,一切都好!我在控制台中遇到同样的问题
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
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下,到底发生了什么事,拜托?))
小智 9
你在这里遇到的是activerecord对数据库属性访问器方法的延迟实例化.
TL; DR你可以使用这样的东西https://github.com/rspec/rspec-rails/issues/1357
基本上,ActiveRecord :: Base类在他们需要之前不会定义任何基于数据库列的setter/getter,通常是通过方法缺失的钩子,尽管可能有其他东西可能导致它们被定义,例如调用Search.find_by_affiliate_id也可能导致定义加载.
我可以提供它如何/为什么以它的方式工作的高级解释,但是可能有更好/更新的资源可以更好地解释它,或者你可以通过ActiveRecord源代码阅读,而有点钝,可以是理解其行为的合理选择.
那么为什么不定义这些方法呢?
当通过继承创建新的ActiveRecord类时ActiveRecord::Base,所有类都知道它是否是预期的表名,但是如果没有连接到数据库则不知道该表有哪些列.在不知道存在哪些列的情况下,它无法知道要定义哪些读取器/写入器.ActiveRecord在加载时不会主动查询数据库,我认为这是一件非常好的事情,因为它允许您加载代码而无需迁移的连接数据库.
什么的ActiveRecord不会被钩住method_missing,responds_to?等,以确定何时被调用在未限定的ActiveRecord类的方法,试图加载当前DB模式和限定读取/写入器/存取方法在其自身上对找到的每个列中,然后重试方法调用以查看它是否已定义.
在你上面的例子,很可能不是的.last,它定义的属性调用,而是.inspect你的终端以打印的运行实例调用Search对象.
要对此进行测试,您可以重新运行上面的示例,但替换Search.last为(s = Search.last).nil?.如果你这样做了,我敢打赌那Search.method_defined?(:affiliate_id)仍然是假的.
希望这能解释为什么这些方法最初没有定义,但后来才开始定义.这也是你无法使用的原因alias_method :aliased_affiliate_id, :affiliate_id,因为affiliat_id在加载时没有定义方法,所以会失败.
对于您要做的事情,您需要确定是否需要有效的数据库连接才能运行这些规范.
如果是这样,您可以触发ActiveRecord类加载其表定义并在规范中定义其读取器/写入器属性以进行此传递.
这里有人遇到了与rspec相同的问题,其中有一个猴子补丁解决方案,它加载了activerecord类的定义:
https://github.com/rspec/rspec-rails/issues/1357
| 归档时间: |
|
| 查看次数: |
3472 次 |
| 最近记录: |