ActiveResource 在开发中 运行 rails 控制台添加额外的 class

ActiveResource adds an extra class when running rails console in development

我们有 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

运行 Rails 控制台正在开发中。

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

所以文档的 class 名称是 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>

文档的 class 只是 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\"}}]}"

我们正在使用 Rails 4.2.10.

究竟是什么原因造成的?我已经检查了配置是否有任何切换 on/off 取决于环境,但我找不到任何东西。

ActiveResource 似乎正在使用 autoloading mechanism 将属性名称动态转换为 classes 以供集合使用。

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

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

如果the constant is not found on Object, it is created within the class that is being initialized (Valuation).

为了让开发以与生产相同的方式工作,您需要绕过触发此自动加载机制。这可以通过 Rails.

中的 require_dependency 方法轻松完成

只需添加

require_dependency 'document'

class Valuation < ActiveResource::Base

Valuation class 之前,一切都应该正常。

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