Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring in Rails 6 tries to load ActiveRecord even when AR is not part of the application #601

Open
p-mongo opened this issue Oct 9, 2019 · 9 comments

Comments

@p-mongo
Copy link

p-mongo commented Oct 9, 2019

If I create a skeleton Rails API application, and then remove ActiveRecord from the application, spring still tries to load AR which ultimately fails and prevents generators etc. from working.

This is a regression in Rails 6 - in Rails 5.2 everything works as expected.

I created two applications, which are identical except for version of Rails used.

https://github.com/p-mongo/tests/tree/master/spring-ar-sqlite-5
https://github.com/p-mongo/tests/tree/master/spring-ar-sqlite-6

Generate the app:

rails new --api spring-ar-sqlite-6
cd spring-ar-sqlite

Edit Gemfile, removing reference to sqlite.

Edit config/application.rb, commenting out ActiveRecord and ActiveStorage:

#require "active_record/railtie"
#require "active_storage/engine"

Run:

rails g controller foo

Result:

butler% rails g controller foo
/home/sandbox/.rbenv/versions/2.6.5/lib/ruby/2.6.0/bundler/rubygems_integration.rb:408:in `block (2 levels) in replace_gem': Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? sqlite3 is not part of the bundle. Add it to your Gemfile. (LoadError)
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/connection_adapters/sqlite3_adapter.rb:13:in `<main>'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/zeitwerk-2.2.0/lib/zeitwerk/kernel.rb:23:in `require'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/connection_adapters/connection_specification.rb:170:in `spec'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/connection_adapters/abstract/connection_pool.rb:1044:in `establish_connection'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/connection_handling.rb:51:in `establish_connection'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/railtie.rb:201:in `block (2 levels) in <class:Railtie>'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/lazy_load_hooks.rb:72:in `class_eval'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/lazy_load_hooks.rb:72:in `block in execute_hook'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/lazy_load_hooks.rb:62:in `with_execution_control'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/lazy_load_hooks.rb:67:in `execute_hook'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/lazy_load_hooks.rb:52:in `block in run_load_hooks'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/lazy_load_hooks.rb:51:in `each'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/lazy_load_hooks.rb:51:in `run_load_hooks'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/base.rb:327:in `<module:ActiveRecord>'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/base.rb:27:in `<main>'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/zeitwerk-2.2.0/lib/zeitwerk/kernel.rb:23:in `require'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:370:in `active_record_configured?'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:287:in `disconnect_database'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:111:in `preload'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:157:in `serve'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:145:in `block in run'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:139:in `loop'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application.rb:139:in `run'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/spring-2.1.0/lib/spring/application/boot.rb:19:in `<top (required)>'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /home/sandbox/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from -e:1:in `<main>'
@rafaelfranca
Copy link
Member

Something in your app is defining ActiveRecord::Base. Spring only try to load it if the constant exists https://github.com/rails/spring/blob/master/lib/spring/application.rb#L370.

@p-mongo
Copy link
Author

p-mongo commented Oct 9, 2019

The AR require is triggered from that line, leading me to believe that something configures AR to be autoloaded, but I don't know how to determine what that would be.

In any event "my app" has no code, as stated in the above description. I generated it using the standard Rails generator and removed AR railtie.

@rafaelfranca
Copy link
Member

oh. Yeah, that is true. ActiveRecord::Base is autoloaded, so of course that code doesn't work. We need to find a way to check if Active Record is loaded without checking for defined?.

@jasnow
Copy link

jasnow commented Oct 9, 2019

Try this "--skip-active-record" with "rails new"

@p-mongo
Copy link
Author

p-mongo commented Oct 10, 2019

rails new --skip-acitve-record --api also omits spring from the generated application. Thus it is a valid workaround but does not fix the problem reported in this issue.

@p-mongo
Copy link
Author

p-mongo commented Oct 14, 2019

I thought simply adding sqlite to the bundle was a sufficient workaround, but per https://stackoverflow.com/questions/58352612/rails-tasks-and-generators-are-failing/58383659#58383659 the application must define a full AR configuration. If this configuration is loaded, i.e. connection(s) to the database are established, this is a rather heavy workaround considering the AR database won't ever be used by any application code.

@coderifous
Copy link

I tripped over this as well deploying an application to Heroku. I did not need ActiveRecord, and simply leaving sqlite installed is not compatible with Heroku. It looks like a few indirect dependencies on ActiveRecord precipitated the autoloading. Anyways, the resolution turns out to be relatively straightfoward.

  • I removed sqlite from my Gemfile
  • deleted config/database.yml
  • Manually required the railties that would NOT result in ActiveRecord loading:
--- a/config/application.rb
+++ b/config/application.rb
@@ -1,6 +1,29 @@
 require_relative 'boot'

-require 'rails/all'
+# require 'rails/all'
+
+  # Removed because ActiveRecord:
+  # active_record/railtie
+  #
+  # Removed because precipitates AR load:
+  # action_mailbox/engine
+  # active_storage/engine
+  # action_text/engine
+
+%w(
+  action_cable/engine
+  active_job/railtie
+  action_mailer/railtie
+  action_controller/railtie
+  action_view/railtie
+  rails/test_unit/railtie
+  sprockets/railtie
+).each do |railtie|
+  begin
+    require railtie
+  rescue LoadError
+  end
+end
  • And finally, removed any reference to active_storage and active_record in my config/environments/*.rb files, e.g.:
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -29,7 +29,7 @@ Rails.application.configure do
   end

   # Store uploaded files on the local file system (see config/storage.yml for options).
-  config.active_storage.service = :local
+  # config.active_storage.service = :local

   # Don't care if the mailer can't send.
   config.action_mailer.raise_delivery_errors = false
@@ -40,10 +40,10 @@ Rails.application.configure do
   config.active_support.deprecation = :log

   # Raise an error on page load if there are pending migrations.
-  config.active_record.migration_error = :page_load
+  # config.active_record.migration_error = :page_load

   # Highlight code that triggered database queries in logs.
-  config.active_record.verbose_query_logs = true
+  # config.active_record.verbose_query_logs = true

Hopefully this helps!

@Reeseman
Copy link

Thanks so much @coderifous ! You really helped me out today

@thinhbui311
Copy link

@coderifous active storage is the point in my case. Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants