[Fix #50897] Autosaving has_one
sets foreign key attribute when unchanged
This commit is contained in:
parent
3528b9df8b
commit
a518b5a9d9
@ -1,3 +1,10 @@
|
||||
* Fix `has_one` association autosave setting the foreign key attribute when it is unchanged.
|
||||
|
||||
This behaviour is also inconsistent with autosaving `belongs_to` and can have unintended side effects like raising
|
||||
an `ActiveRecord::ReadOnlyAttributeError` when the foreign key attribute is marked as read-only.
|
||||
|
||||
*Joshua Young*
|
||||
|
||||
* Remove deprecated behavior that would rollback a transaction block when exited using `return`, `break` or `throw`.
|
||||
|
||||
*Rafael Mendonça França*
|
||||
|
@ -458,7 +458,8 @@ def save_has_one_association(reflection)
|
||||
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
||||
|
||||
primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
|
||||
record[foreign_key] = _read_attribute(primary_key)
|
||||
association_id = _read_attribute(primary_key)
|
||||
record[foreign_key] = association_id unless record[foreign_key] == association_id
|
||||
end
|
||||
association.set_inverse_instance(record)
|
||||
end
|
||||
|
@ -302,6 +302,13 @@ def test_callbacks_firing_order_on_save
|
||||
eye.update(iris_attributes: { color: "blue" })
|
||||
assert_equal [false, false, false, false], eye.after_save_callbacks_stack
|
||||
end
|
||||
|
||||
def test_foreign_key_attribute_is_not_set_unless_changed
|
||||
eye = Eye.create!(iris_with_read_only_foreign_key_attributes: { color: "honey" })
|
||||
assert_nothing_raised do
|
||||
eye.update!(override_iris_with_read_only_foreign_key_color: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase
|
||||
|
@ -4,19 +4,20 @@ class Eye < ActiveRecord::Base
|
||||
attr_reader :after_create_callbacks_stack
|
||||
attr_reader :after_update_callbacks_stack
|
||||
attr_reader :after_save_callbacks_stack
|
||||
attr_writer :override_iris_with_read_only_foreign_key_color
|
||||
|
||||
# Callbacks configured before the ones has_one sets up.
|
||||
after_create :trace_after_create
|
||||
after_update :trace_after_update
|
||||
after_save :trace_after_save
|
||||
after_create :trace_after_create, if: :iris
|
||||
after_update :trace_after_update, if: :iris
|
||||
after_save :trace_after_save, if: :iris
|
||||
|
||||
has_one :iris
|
||||
accepts_nested_attributes_for :iris
|
||||
|
||||
# Callbacks configured after the ones has_one sets up.
|
||||
after_create :trace_after_create2
|
||||
after_update :trace_after_update2
|
||||
after_save :trace_after_save2
|
||||
after_create :trace_after_create2, if: :iris
|
||||
after_update :trace_after_update2, if: :iris
|
||||
after_save :trace_after_save2, if: :iris
|
||||
|
||||
def trace_after_create
|
||||
(@after_create_callbacks_stack ||= []) << !iris.persisted?
|
||||
@ -32,8 +33,23 @@ def trace_after_save
|
||||
(@after_save_callbacks_stack ||= []) << iris.has_changes_to_save?
|
||||
end
|
||||
alias trace_after_save2 trace_after_save
|
||||
|
||||
has_one :iris_with_read_only_foreign_key, class_name: "IrisWithReadOnlyForeignKey", foreign_key: :eye_id
|
||||
accepts_nested_attributes_for :iris_with_read_only_foreign_key
|
||||
|
||||
before_save :set_iris_with_read_only_foreign_key_color_to_blue, if: -> {
|
||||
iris_with_read_only_foreign_key && @override_iris_with_read_only_foreign_key_color
|
||||
}
|
||||
|
||||
def set_iris_with_read_only_foreign_key_color_to_blue
|
||||
iris_with_read_only_foreign_key.color = "blue"
|
||||
end
|
||||
end
|
||||
|
||||
class Iris < ActiveRecord::Base
|
||||
belongs_to :eye
|
||||
end
|
||||
|
||||
class IrisWithReadOnlyForeignKey < Iris
|
||||
attr_readonly :eye_id
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user