diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 7edfec9903add..d2eb2d0ed3983 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -587,18 +587,22 @@ def check_pending!(connection = Base.connection) end def load_schema_if_pending! - if Base.connection.migration_context.needs_migration? || !Base.connection.migration_context.any_migrations? + current_config = Base.connection_config + all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env) + + unless all_configs.all? { |config| Tasks::DatabaseTasks.schema_up_to_date?(config.config) } # Roundtrip to Rake to allow plugins to hook into database initialization. root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root FileUtils.cd(root) do - current_config = Base.connection_config Base.clear_all_connections! system("bin/rails db:test:prepare") - # Establish a new connection, the old database may be gone (db:test:prepare uses purge) - Base.establish_connection(current_config) end - check_pending! end + + # Establish a new connection, the old database may be gone (db:test:prepare uses purge) + Base.establish_connection(current_config) + + check_pending! end def maintain_test_schema! #:nodoc: diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 300e67b0aa027..387004c71cfb3 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -332,10 +332,21 @@ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = end ActiveRecord::InternalMetadata.create_table ActiveRecord::InternalMetadata[:environment] = environment + ActiveRecord::InternalMetadata[:schema_sha1] = schema_sha1(file) ensure Migration.verbose = verbose_was end + def schema_up_to_date?(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env, spec_name = "primary") + file ||= dump_filename(spec_name, format) + + return true unless File.exist?(file) + + ActiveRecord::Base.establish_connection(configuration) + return false unless ActiveRecord::InternalMetadata.table_exists? + ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file) + end + def dump_schema(configuration, format = ActiveRecord::Base.schema_format, spec_name = "primary") # :nodoc: require "active_record/schema_dumper" filename = dump_filename(spec_name, format) @@ -467,6 +478,10 @@ def each_local_configuration def local_database?(configuration) configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"]) end + + def schema_sha1(file) + Digest::SHA1.hexdigest(File.read(file)) + end end end end diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index 83e63718dfa7b..17fc004c4587f 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -232,10 +232,7 @@ class UserTest < ActiveSupport::TestCase assert_successful_test_run("models/user_test.rb") end - # TODO: would be nice if we could detect the schema change automatically. - # For now, the user has to synchronize the schema manually. - # This test case serves as a reminder for this use case. - test "manually synchronize test schema after rollback" do + test "automatically synchronizes test schema after rollback" do output = rails("generate", "model", "user", "name:string") version = output.match(/(\d+)_create_users\.rb/)[1] @@ -268,10 +265,6 @@ class UserTest < ActiveSupport::TestCase end RUBY - assert_successful_test_run "models/user_test.rb" - - rails "db:test:prepare" - assert_unsuccessful_run "models/user_test.rb", <<-ASSERTION Expected: ["id", "name"] Actual: ["id", "name", "age"]