rails: Unexpected rake task behavior change in Rails 5.2

Steps to reproduce

  1. Initialize a Rails app (5.2)
  2. Add config.after_initialize { raise "foo" }
  3. Run rake db:create

Expected behavior

Before 5.2, the after_initialize block will not be executed so the database can be created successfully

Actual behavior

The app crashed because the after_initialize block

System configuration

Rails version: 5.2

Ruby version: 2.4.1

Notes

I think this is an issue because before 5.2 we might add some database related logics in after_initialize block. And since running tasks like db:create won’t initialize the whole app this can work. Like:

module Sample
  class Application < Rails::Application
    config.after_initialize do
      # connect to database
    end
  end
end

But after upgrade to 5.2 the code won’t work because the logic will hit the database first before actually execute the rake task (db:create). And we can’t find this behavior change in changelog or documents.

Also, I found this issue is cause by this commit. Before this commit some of the rake tasks will only run load_config as prerequisite. But now load_config has the environment prerequisite so the app will be fully initialized.

So I think either we change this behavior back, or we should document about it.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 18 (12 by maintainers)

Commits related to this issue

Most upvoted comments

Hey team, we’ve also hit this problem as we have a few cases where we reference constants in our initialisers and our factories (which are being loaded as a part of after_initialize). @bwillis – how did you end up going about avoiding loading factories in after_initialize? @aried3r – have you found a solution for your if Product.table_exists? example? Thanks in advance!

Should quickly add we’ve managed to solve our issue by guarding the areas where classes were being loaded with ActiveRecord::Base.connected? – we had a few guards of ActiveRecord::Base.connection.data_source_exists?("model") but these seemed to no longer behave the way they did in Rails 4.x (we have only recently upgraded to 5.2).

By the way, just interested, why do need to use model with initializers?

I think the question here should be whether the use of models is not allowed in after_initialize blocks. With this change it means that all after_initialize blocks should not contain any code that attempts to connect to the database otherwise, rake db:create will not work.

@bwillis – how did you end up going about avoiding loading factories in after_initialize?

gem 'factory_bot_rails', require: false

Then loading it where we needed it explicitly, which, for us, was in our spec helper:

require 'factory_bot_rails'