在开发中运行rails控制台时,ActiveResource会添加一个额外的类

jvn*_*ill 6 ruby-on-rails activeresource

我们有2个模型:估价和文件.两者都在微服务中,因此我们使用ActiveResource来访问它们.

class Valuation < ActiveResource::Base
  self.site = "#{config.valuation_service.base_url}/valuations"
  self.include_root_in_json = false
end

class Document < ActiveResource::Base
  self.site = "#{config.valuation_service.base_url}/documents"
  self.include_root_in_json = true
end
Run Code Online (Sandbox Code Playgroud)

在开发中运行Rails控制台.

>> Valuation.new(documents: [{ title: 'Foo' }])
=> <Valuation:0x007f9af85f1708 @attributes={"documents"=>[#<Valuation::Document:0x007f9af85f0970 @attributes={"title"=>"Foo"}, @prefix_options={}, @persisted=false>]}, @prefix_options={}, @persisted=false>
Run Code Online (Sandbox Code Playgroud)

所以文档的类名是Valuation:Document.在生产中运行rails控制台时

>> Valuation.new(documents: [{ title: 'Foo' }])
=> <Valuation:0x007f9af595b478 @attributes={"documents"=>[#<Document:0x007f9af595a500 @attributes={"title"=>"Foo"}, @prefix_options={}, @persisted=false>]}, @prefix_options={}, @persisted=false>
Run Code Online (Sandbox Code Playgroud)

文档的类只是Document和它一样尊重配置include_root_in_json.

更大的问题是在调用.to_json对象时.

# development
>> Valuation.new(documents: [{ title: 'Foo' }]).to_json
=> "{\"documents\":[{\"title\":\"Foo\"}]}"

# production
>> Valuation.new(documents: [{ title: 'Foo' }]).to_json
=> "{\"documents\":[{\"document\":{\"title\":\"Foo\"}}]}"
Run Code Online (Sandbox Code Playgroud)

我们正在使用Rails 4.2.10.

究竟是什么导致了这个?我已经检查过配置是否有任何切换开/关取决于环境但我找不到任何.

Lau*_*nen 4

ActiveResource 似乎正在使用自动加载机制来动态地将属性名称转换为集合的类。

因此,开发和生产之间的差异是由于急切加载造成的。在生产中,所有文件都会预先加载,因此当您运行控制台时,所有常量都已经存在。

当您在开发模式下运行控制台时,ActiveResource 尝试定义属性的类名称,但该机制不适用于您的用例。

如果在 上找不到常量Object则在正在初始化的类中创建该常量( Valuation)。

为了使开发以与生产相同的方式工作,您需要绕过触发此自动加载机制。这可以通过 Rails 的方法轻松完成require_dependency

只需添加

require_dependency 'document'

class Valuation < ActiveResource::Base
Run Code Online (Sandbox Code Playgroud)

上课前Valuation,一切都应该正常进行。

此行确保Document在任何人尝试创建类的实例之前已经加载常量Valuation,并且不会使用自动加载机制。