diff options
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/lib/active_record/locking/optimistic.rb | 1 | ||||
-rw-r--r-- | activerecord/lib/active_record/migration.rb | 10 | ||||
-rw-r--r-- | activerecord/lib/active_record/persistence.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 8 | ||||
-rw-r--r-- | activerecord/test/cases/associations/left_outer_join_association_test.rb | 1 | ||||
-rw-r--r-- | activerecord/test/cases/calculations_test.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/dirty_test.rb | 22 | ||||
-rw-r--r-- | activerecord/test/cases/migration_test.rb | 19 | ||||
-rw-r--r-- | activerecord/test/cases/relations_test.rb | 6 |
9 files changed, 66 insertions, 5 deletions
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index e1e24e2814..bf17f27e68 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -78,6 +78,7 @@ module ActiveRecord end def _update_record(attribute_names = self.attribute_names) + attribute_names &= self.class.column_names return super unless locking_enabled? return 0 if attribute_names.empty? diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 5322571820..663b3c590a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -140,6 +140,7 @@ module ActiveRecord class ConcurrentMigrationError < MigrationError #:nodoc: DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze + RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock".freeze def initialize(message = DEFAULT_MESSAGE) super @@ -1355,12 +1356,17 @@ module ActiveRecord def with_advisory_lock lock_id = generate_migrator_advisory_lock_id - got_lock = Base.connection.get_advisory_lock(lock_id) + connection = Base.connection + got_lock = connection.get_advisory_lock(lock_id) raise ConcurrentMigrationError unless got_lock load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock yield ensure - Base.connection.release_advisory_lock(lock_id) if got_lock + if got_lock && !connection.release_advisory_lock(lock_id) + raise ConcurrentMigrationError.new( + ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE + ) + end end MIGRATOR_SALT = 2053462845 diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 88b971327b..4eecbd0629 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -704,6 +704,7 @@ module ActiveRecord # Updates the associated record with values matching those of the instance attributes. # Returns the number of affected rows. def _update_record(attribute_names = self.attribute_names) + attribute_names &= self.class.column_names attributes_values = arel_attributes_with_values_for_update(attribute_names) if attributes_values.empty? rows_affected = 0 @@ -721,6 +722,7 @@ module ActiveRecord # Creates a record with values matching those of the instance attributes # and returns its id. def _create_record(attribute_names = self.attribute_names) + attribute_names &= self.class.column_names attributes_values = arel_attributes_with_values_for_create(attribute_names) new_id = self.class._insert_record(attributes_values) diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 71afbc1041..42b451241d 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -611,7 +611,13 @@ module ActiveRecord if can_find_inverse_of_automatically?(self) inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym - reflection = klass._reflect_on_association(inverse_name) + begin + reflection = klass._reflect_on_association(inverse_name) + rescue NameError + # Give up: we couldn't compute the klass type so we won't be able + # to find any associations either. + reflection = false + end if valid_inverse_reflection?(reflection) return inverse_name diff --git a/activerecord/test/cases/associations/left_outer_join_association_test.rb b/activerecord/test/cases/associations/left_outer_join_association_test.rb index 7b5c394177..0e54e8c1b0 100644 --- a/activerecord/test/cases/associations/left_outer_join_association_test.rb +++ b/activerecord/test/cases/associations/left_outer_join_association_test.rb @@ -5,6 +5,7 @@ require "models/post" require "models/comment" require "models/author" require "models/essay" +require "models/category" require "models/categorization" require "models/person" diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index f5971bedfc..74228b2796 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -246,8 +246,6 @@ class CalculationsTest < ActiveRecord::TestCase posts = Post.includes(:comments).order("comments.id").distinct assert_queries(1) { assert_equal 11, posts.count } assert_queries(1) { assert_equal 11, posts.count(:all) } - assert_queries(1) { assert_equal 11, posts.size } - assert_queries(1) { assert_equal 11, posts.load.size } end def test_distinct_count_all_with_custom_select_and_order diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 14c4e3cbd4..0791811d94 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -736,6 +736,28 @@ class DirtyTest < ActiveRecord::TestCase assert record.save end + test "virtual attributes are not written with partial_writes off" do + original_partial_writes = ActiveRecord::Base.partial_writes + begin + ActiveRecord::Base.partial_writes = false + klass = Class.new(ActiveRecord::Base) do + self.table_name = "people" + attribute :non_persisted_attribute, :string + end + + record = klass.new(first_name: "Sean") + record.non_persisted_attribute_will_change! + + assert record.save + + record.non_persisted_attribute_will_change! + + assert record.save + ensure + ActiveRecord::Base.partial_writes = original_partial_writes + end + end + test "mutating and then assigning doesn't remove the change" do pirate = Pirate.create!(catchphrase: "arrrr") pirate.catchphrase << " matey!" diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index a4b8664a85..c241ddc807 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -693,6 +693,25 @@ class MigrationTest < ActiveRecord::TestCase assert_no_column Person, :last_name, "without an advisory lock, the Migrator should not make any changes, but it did." end + + def test_with_advisory_lock_raises_the_right_error_when_it_fails_to_release_lock + migration = Class.new(ActiveRecord::Migration::Current).new + migrator = ActiveRecord::Migrator.new(:up, [migration], 100) + lock_id = migrator.send(:generate_migrator_advisory_lock_id) + + e = assert_raises(ActiveRecord::ConcurrentMigrationError) do + silence_stream($stderr) do + migrator.send(:with_advisory_lock) do + ActiveRecord::Base.connection.release_advisory_lock(lock_id) + end + end + end + + assert_match( + /#{ActiveRecord::ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE}/, + e.message + ) + end end private diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 18e0bed5b6..cf65789b97 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -976,6 +976,12 @@ class RelationTest < ActiveRecord::TestCase assert_queries(1) { assert_equal 11, posts.load.size } end + def test_size_with_eager_loading_and_custom_order_and_distinct + posts = Post.includes(:comments).order("comments.id").distinct + assert_queries(1) { assert_equal 11, posts.size } + assert_queries(1) { assert_equal 11, posts.load.size } + end + def test_update_all_with_scope tag = Tag.first Post.tagged_with(tag.id).update_all title: "rofl" |