在我的 Ruby (2.3.0) on Rails (5.0.1) 项目中,自动加载(和重新加载)通常工作正常。但是,在开发模式下,我偶尔会看到如下错误:
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 自动加载行为的很好的解释。 This answer提供了一个有用的解释,它从 this blog post at urbanautomaton.com 中获取.
总结:
基本上,Rails 首先使用 Ruby 的常量查找。如果失败,那么它有自己的查找,如果
config.autoload_paths += %W(#{config.root}/foo) 不在,Rails 将找不到 app/foo/bar.rb添加到 config/application.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_missingpasses 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:module Foo module Bar Baz # Module.nesting => [Foo::Bar, Foo] endend
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 => []module Foo::Bar Baz # Module.nesting => [Foo::Bar] endWhile 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::Bazis referred to, then, Rails will attempt to load the following constants in turn, until it finds one that is already loaded:
Foo::Bar::BazFoo::BazBazAs soon as an already-loaded constant
Bazis encountered, Rails knows this cannot be theBazit is looking for, and the algorithm raises aNameError.
如果没有关于代码设置方式的更多细节,很难说出到底是什么导致了您的问题,但希望了解 Rails 中自动加载的情况可能会有所帮助。我强烈建议您阅读上面链接的博文和答案。
针对可能的解决方案进行编辑:
确保将“app/models/foo”添加到 config/application.rb 中的 autoload_load 路径 - 或者将“foo”移动到 app/models/concerns,默认情况下应该在那里。
经常添加显式的 require 语句会有所帮助——尤其是在开发中加载正确但测试中加载不正确的情况下。我最近通过添加一个需要我所有嵌套文件的文件(我有一个不反射(reflect)我的命名空间结构的目录结构)然后在我的测试助手中需要该文件来解决这个问题。
第二次编辑
包括与问题相关的信息,为什么常量可能只成功加载一次。
来自 the same blog post :
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?
> Foo::Bar.print_qux I'm in Foo! => nil > Foo::Bar.print_quxNameError: 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:
> Qux => "I'm at the root!" > Foo::Bar.print_qux I'm at the root! => nil > Foo::Bar.print_qux I'm at the root! => nilA 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.
关于ruby-on-rails - 为什么 Ruby on Rails 在编辑代码后会虚假地引发 0x104567910?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41467451/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
这似乎应该有一个直截了当的答案,但在Google上花了很多时间,所以我找不到它。这可能是缺少正确关键字的情况。在我的RoR应用程序中,我有几个模型共享一种特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。这会导致模型中出现大量重复(甚至单元测试中会出现更多重复),但我不确定如何让它更DRY。我能想到几个可能的方向...按照“validates_url_format_of”插件,但这只会让验证干给这个特殊的字符串它自己的模型,但这看起来很像重溶液为这个特殊的字符串创建一个ruby类,但是我如何得到ActiveRecord关联这个类模型
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)
如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题