We have 2 Models: Valuation and Document. Both are in a microservice so we use ActiveResource to access them.
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
Running the Rails console in development.
>> Valuation.new(documents: [{ title: 'Foo' }])
=> <Valuation:0x007f9af85f1708 @attributes={"documents"=>[#<Valuation::Document:0x007f9af85f0970 @attributes={"title"=>"Foo"}, @prefix_options={}, @persisted=false>]}, @prefix_options={}, @persisted=false>
so the document's class name is Valuation:Document
. When you run the rails console in production
>> Valuation.new(documents: [{ title: 'Foo' }])
=> <Valuation:0x007f9af595b478 @attributes={"documents"=>[#<Document:0x007f9af595a500 @attributes={"title"=>"Foo"}, @prefix_options={}, @persisted=false>]}, @prefix_options={}, @persisted=false>
The class of the document is just Document
and it respects the config like include_root_in_json
.
The bigger issue is when calling .to_json
on the objects.
# development
>> Valuation.new(documents: [{ title: 'Foo' }]).to_json
=> "{\"documents\":[{\"title\":\"Foo\"}]}"
# production
>> Valuation.new(documents: [{ title: 'Foo' }]).to_json
=> "{\"documents\":[{\"document\":{\"title\":\"Foo\"}}]}"
We are using Rails 4.2.10.
What exactly is causing this? I've checked configs if there is anything toggled on/off depending on the environment but I can't find any.
ActiveResource seems to be using an autoloading mechanism for dynamically turning the attribute names into classes for collections.
Because of this, the difference between development and production are due to eager loading. In production all the files are eager loaded and therefore all the constants already exists when you run the console.
When you are running the console in development mode, ActiveResource tries to define the class name for the attribute, but the mechanism won't work for your use case.
If the constant is not found on Object
, it is created within the class that is being initialized (Valuation
).
In order to get development working the same way as production, you'll need to bypass triggering this autoloading mechanism. This can be done easily with require_dependency
method from Rails.
Just add
require_dependency 'document'
class Valuation < ActiveResource::Base
before the Valuation
class, and everything should work just fine.
This line makes sure that the Document
constant has already been loaded before anyone tries to create an instance of the Valuation
class, and the autoloading mechanism won't used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With