aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb1
-rw-r--r--activerecord/lib/active_record/migration.rb10
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/reflection.rb8
-rw-r--r--activerecord/test/cases/associations/left_outer_join_association_test.rb1
-rw-r--r--activerecord/test/cases/calculations_test.rb2
-rw-r--r--activerecord/test/cases/dirty_test.rb22
-rw-r--r--activerecord/test/cases/migration_test.rb19
-rw-r--r--activerecord/test/cases/relations_test.rb6
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"