Unable to autoload constant Foo::Bar,expected /app/models/foo/bar.rb to define it
这是意外的,因为:
>第一个请求工作正常(它已经自动加载过一次).
>它仅在编辑代码并发送新请求后出现.
>并非总是如此.我无法弄清楚为什么有时它无法重新加载.
>文件(foo / bar.rb)确实定义了Foo :: Bar.
而且,foo / bar.rb的代码很简单:
module Foo class Bar < CustomRecord end end
简单的解决方法是重新启动服务器,然后再次发送请求(总是成功). FWIW,我正在使用zeus server
.
我最好的猜测是没有重新加载某些东西,但我不确定如何进行调试.我似乎无法指出导致问题的任何具体行动.有时编辑代码会导致它发生,有时不会.
解决方法
摘要:
基本上,Rails首先使用Ruby的常量查找.如果失败,那么它有自己的查找,如果错过了文件
>它们不在自动加载路径中(如果config.autoload_paths =%W(#{config.root} / foo)未添加到config / application.rb,则Rails将找不到app / foo / bar.rb)
>不遵循目录名称/命名空间约定
它将在app / foo / bar.rb中找到Foo :: Bar,如果它被定义为:
module Foo class Bar end end
但不是
module Foo module Bar end end
>引用不同名称空间中的常量,而不在另一个已自动加载的文件中指示该名称空间
At this point,we’ve only seen how a single constant name maps to a
single file name. But as we know,a constant reference in Ruby can
resolve to a number of different constant definitions,which vary
depending on the nesting in which the reference was made. How does
Rails handle this?The answer is,“partially”. As
Module#const_missing
passes no nesting
information to the receiver,Rails does not know the nesting in which
the reference was made,and it must make an assumption. For any
reference to a constantFoo::Bar::Baz
,it assumes the following:06002
end
In other words,it assumes the maximum nesting possible for a given constant
reference. The example reference is therefore treated exactly the same
as the following:
Foo::Bar::Baz # Module.nesting => []
06003
While there’s
been a significant loss of information,Rails does have some extra
information it can use. It knows that Ruby Failed to resolve this
particular constant reference using its regular lookup,meaning that
whatever constant it should refer to cannot be already loaded.When
Foo::Bar::Baz
is referred to,then,Rails will attempt to load
the following constants in turn,until it finds one that is already
loaded:
Foo::Bar::Baz
Foo::Baz
Baz
As soon as an already-loaded constant
Baz
is encountered,Rails knows this cannot be theBaz
it is looking for,
and the algorithm raises aNameError
.
如果没有关于如何设置代码的详细信息,很难说出究竟是什么导致了您的问题,但希望了解Rails中自动加载的情况可能会有所帮助.我强烈建议您阅读上面链接的博文和答案.
编辑可能的解决方案:
确保将’app / models / foo’添加到config / application.rb中的autoload_load路径 – 或将’foo’移动到app / models / concern,默认情况下应该存在.
通常添加显式require语句会有所帮助 – 特别是如果事情在开发中正确加载但在测试中没有.我最近通过添加一个需要所有嵌套文件的文件解决了这个问题(我的目录结构没有镜像我的命名空间结构),然后在我的测试助手中需要该文件.
第二次编辑
包括与问题相关的信息,为什么常量只能成功加载一次.
If constants are loaded only when they’re first encountered at
runtime,then by necessity their load order depends on the individual
execution path. This can mean that the same constant reference
resolves to different constant definitions in two runs of the same
code. Worse still,the same constant reference twice in a row can give
different results.Let’s go back to our last example. What happens if we call .print_qux
twice?06004
NameError: uninitialized constant Foo::Bar::Qux This is disastrous!
First we’ve been given the wrong result,and then we’ve been
incorrectly told that the constant we referred to doesn’t exist. What
on earth led to this?The first time,as before,is down to the loss of nesting information.
Rails can’t know that Foo::Qux isn’t what we’re after,so once it
realises that Foo::Bar::Qux does not exist,it happily loads it.The second time,however,Foo::Qux is already loaded. So our reference
can’t have been to that constant,otherwise Ruby would have resolved
it,and autoloading would never have been invoked. So the lookup
terminates with a NameError,even though our reference could (and
should) have resolved to the as-yet-unloaded ::Qux.We can fix this by referring to ::Qux first,ensuring that it’s loaded
for Ruby to resolve the reference:06005
A funny thing has happened here. In order to get correct behavIoUr,we
deliberately loaded the constant we needed before we used it (albeit
indirectly,by referring to it,rather than loading the file that
defined it).But wait; isn’t this suspicIoUsly close to explicitly loading our
dependencies with require,the very thing autoloading was supposed to
save us from?To be fair,we could also have fixed the issue by fully qualifying all of our constant references,i.e. making sure that within .print_qux we referred to ::Qux and not the ambiguous Qux. But this still costs us our existing intuitions about Ruby’s behavIoUr. Moreover,without intimate knowledge of the autoloading process,we would have been hard pressed to deduce that this was necessary.