我在控制台中遇到同样的问题
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
有人可以解释一下,到底发生了什么事,拜托?))
解决方法
TL; DR你可以使用像这样的https://github.com/rspec/rspec-rails/issues/1357
基本上,ActiveRecord :: Base类在他们需要之前不会定义任何基于数据库列的setter / getter,通常是通过方法缺失的钩子,尽管可能有其他东西可能导致它们被定义,例如调用Search.find_by_affiliate_id也可能导致加载定义.
我可以提供它如何/为什么以它的方式工作的高级解释,但是可能有更好/更新的资源可以更好地解释它,或者你可以通过ActiveRecord源代码阅读,而有点钝,可以是理解其行为的合理选择.
那么为什么不定义这些方法呢?
当通过继承ActiveRecord :: Base创建新的ActiveRecord类时,所有类都知道它是否是预期的表名,但是如果没有连接到数据库,则不知道该表有哪些列.在不知道存在哪些列的情况下,它无法知道要定义哪些读取器/写入器. ActiveRecord在加载时不会主动查询数据库,我认为这是一件非常好的事情,因为它允许您加载代码而无需迁移的连接数据库.
ActiveRecord的作用是挂钩method_missing,responds_to?等,以确定何时在未定义的ActiveRecord类上调用方法,尝试加载当前的db模式并为每列定义自己的reader / writer / accessor方法它找到,然后重试方法调用以查看它是否已定义.
在上面的示例中,可能不是定义属性的.last调用,而是终端运行的.inspect调用,以便打印Search对象的实例.
要对此进行测试,您可以重新运行上面的示例,但将Search.last替换为(s = Search.last).nil?.如果你这样做了,我敢打赌Search.method_defined?(:affiliate_id)仍然是假的.
希望这能解释为什么这些方法最初没有定义,但后来才开始定义.这也是你不能使用alias_method:aliased_affiliate_id,:affiliate_id的原因,因为在加载时没有定义affiliat_id方法会失败.
对于您要做的事情,您需要确定是否需要有效的数据库连接才能运行这些规范.
如果是这样,您可以触发ActiveRecord类加载其表定义并在规范中定义其读取器/写入器属性以进行此传递.