ActiveResource adds an extra class when running rails console in development
Asked Answered
S

1

6

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.

Songsongbird answered 5/4, 2018 at 6:15 Comment(2)
A few questions. What does it look like for the test environment? What version of the activeresource gem are you using? Can you repro this in a fresh rails install?Subscript
ActiveResource is 4.1.0. Haven't really tried to reproduce in a rails install but can probably do that quickly in a sec.Songsongbird
A
4

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.

Apure answered 5/5, 2018 at 9:27 Comment(1)
testing this initially and it works! thank you. i'll have to run a few more test on tuesday before I award the bounty but so far, so good.Songsongbird

© 2022 - 2024 — McMap. All rights reserved.