1

I've created multiple rails application from scratch, but somehow I'm not able fix Circular dependency error. For reproducing the error, I created new app with following commands,

rails new circular_test -d mysql
cd circular_test
rails g model MyImage
rails g scaffold MachineImage
rm db/migrate/20170419063916_create_my_image.rb
rails db:create
rails db:migrate

After this I edited the models, which are as follows,

app/models/machine_image.rb

class MachineImage < ApplicationRecord
   AVAILABLE_FLAVORS = { "MyImage" => MyImage}
end

app/models/my_image.rb

class MyImage < MachineImage
end

Everything else was left with default setting. Nothing was changed. Note that, MyImage is inheriting from MachineImage, instead of ApplicationRecord. When I ran this application in development environment, everything works. But when I run the application in production mode (I made sure db:create & db:migrate is done for prod environment as well),

RAILS_ENV=production rails s

I get following error on running above command,

=> Booting Puma
=> Rails 5.0.2 application starting in production on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
Exiting
/Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:509:in `load_missing_constant': Circular dependency detected while autoloading constant MyImage (RuntimeError)
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:203:in `const_missing'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:543:in `load_missing_constant'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:203:in `const_missing'
    from /Users/abhigup/Work/git/circular_test/app/models/machine_image.rb:2:in `<class:MachineImage>'
    from /Users/abhigup/Work/git/circular_test/app/models/machine_image.rb:1:in `<top (required)>'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:293:in `require'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:293:in `block in require'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:259:in `load_dependency'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:293:in `require'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:380:in `block in require_or_load'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:37:in `block in load_interlock'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies/interlock.rb:12:in `block in loading'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/concurrency/share_lock.rb:150:in `exclusive'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies/interlock.rb:11:in `loading'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:37:in `load_interlock'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:358:in `require_or_load'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:511:in `load_missing_constant'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:203:in `const_missing'
    from /Users/abhigup/Work/git/circular_test/app/models/my_image.rb:1:in `<top (required)>'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:293:in `require'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:293:in `block in require'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:259:in `load_dependency'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:293:in `require'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:380:in `block in require_or_load'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:37:in `block in load_interlock'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies/interlock.rb:12:in `block in loading'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/concurrency/share_lock.rb:150:in `exclusive'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies/interlock.rb:11:in `loading'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:37:in `load_interlock'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:358:in `require_or_load'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:336:in `depend_on'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/activesupport-5.0.2/lib/active_support/dependencies.rb:252:in `require_dependency'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/engine.rb:476:in `block (2 levels) in eager_load!'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/engine.rb:475:in `each'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/engine.rb:475:in `block in eager_load!'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/engine.rb:473:in `each'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/engine.rb:473:in `eager_load!'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/engine.rb:354:in `eager_load!'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/application/finisher.rb:59:in `each'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/application/finisher.rb:59:in `block in <module:Finisher>'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/initializable.rb:30:in `instance_exec'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/initializable.rb:30:in `run'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/initializable.rb:55:in `block in run_initializers'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:226:in `block in tsort_each'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:429:in `each_strongly_connected_component_from'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:347:in `block in each_strongly_connected_component'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `call'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each_strongly_connected_component'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:224:in `tsort_each'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:203:in `tsort_each'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/initializable.rb:54:in `run_initializers'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/application.rb:352:in `initialize!'
    from /Users/abhigup/Work/git/circular_test/config/environment.rb:5:in `<top (required)>'
    from /Users/abhigup/Work/git/circular_test/config.ru:3:in `require_relative'
    from /Users/abhigup/Work/git/circular_test/config.ru:3:in `block in <main>'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/builder.rb:55:in `instance_eval'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/builder.rb:55:in `initialize'
    from /Users/abhigup/Work/git/circular_test/config.ru:in `new'
    from /Users/abhigup/Work/git/circular_test/config.ru:in `<main>'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/builder.rb:49:in `eval'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/builder.rb:49:in `new_from_string'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/builder.rb:40:in `parse_file'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/server.rb:318:in `build_app_and_options_from_config'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/server.rb:218:in `app'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/commands/server.rb:59:in `app'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/server.rb:353:in `wrapped_app'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/rack-2.0.1/lib/rack/server.rb:282:in `start'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/commands/server.rb:79:in `start'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/commands/commands_tasks.rb:90:in `block in server'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/commands/commands_tasks.rb:85:in `tap'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/commands/commands_tasks.rb:85:in `server'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/railties-5.0.2/lib/rails/commands.rb:18:in `<top (required)>'
    from /Users/abhigup/Work/git/circular_test/bin/rails:9:in `require'
    from /Users/abhigup/Work/git/circular_test/bin/rails:9:in `<top (required)>'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/spring-2.0.1/lib/spring/client/rails.rb:28:in `load'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/spring-2.0.1/lib/spring/client/rails.rb:28:in `call'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/spring-2.0.1/lib/spring/client/command.rb:7:in `call'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/spring-2.0.1/lib/spring/client.rb:30:in `run'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/spring-2.0.1/bin/spring:49:in `<top (required)>'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/spring-2.0.1/lib/spring/binstub.rb:31:in `load'
    from /Users/abhigup/.rvm/gems/ruby-2.2.2/gems/spring-2.0.1/lib/spring/binstub.rb:31:in `<top (required)>'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:69:in `require'
    from /Users/abhigup/.rvm/rubies/ruby-2.2.2/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:69:in `require'
    from /Users/abhigup/Work/git/circular_test/bin/spring:15:in `<top (required)>'
    from bin/rails:3:in `load'
    from bin/rails:3:in `<main>'

I was able to solve the problem by making config.eager_load = false in production.rb, but that is not ideal way to solve this issue. To addon, in my previous application I had similar structure, but it works flawlessly in production mode. Only difference is, that it is using SQLite. Is MySQL creating issue with this kind of structure? If not, What is the ideal way to solve this issue?

Note: I've tried looked into this, but it doesn't apply to me. As this error is related to load_missing_constant.

Ruby version: 2.2.2

Rails version: 5.0.2

OS: macOS Sierra 10.12.4

MySQL version: 5.7.17 Homebrew

Update: I found this article, which talks about possible reason. But it didn't specify, why the logic fails only when I try to use MySQL.

Community
  • 1
  • 1
Abhishek
  • 6,912
  • 14
  • 59
  • 85
  • Try putting `MyImage` in an initializer. That should cause Rails to load `MyImage` first. – fylooi Apr 19 '17 at 11:52
  • But `MyImage < MachineImage`, would force `MachineImage` to be called and again it will run in infinite circular loop. – Abhishek Apr 20 '17 at 06:21

1 Answers1

2

I would say that superclass shouldn't really know about sublclasses, however if you have to do so, in your specific case instead of having a constant AVAILABLE_FLAVORS, make it a class method:

 def self.available_flavors
  { "MyImage" => MyImage}
 end

This method won't be called when loading the class, then no circular dependency is there.

  • Nice workaround! +1 for that. But I'm using similar thing in other project & it works. What could be the reason for that? Also, why does it work with SQLite but not for MySQL? – Abhishek Apr 19 '17 at 10:19