Skip to content

Commit ebd7cc6

Browse files
Chris Thompsontenderlove
authored andcommitted
Fix rails#8856 Ensure has_one association=(associate) triggers save.
activerecord/lib/active_record/associations.rb states: # [association=(associate)] # Assigns the associate object, extracts the primary key, sets it as the foreign key, # and saves the associate object. Since commit 42dd5d9 to fix rails#7191, this is no longer the case if the associate has changed, but is the same object. For example: # Pirate has_one :ship pirate = Pirate.create!(catchphrase: "A Pirate") ship = pirate.build_ship(name: 'old name') ship.save! ship.name = 'new name' pirate.ship = ship That last line should trigger a save. Although we are not changing the association, the associate (ship) has changed.
1 parent e8e2f01 commit ebd7cc6

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

activerecord/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Trigger a save on `has_one association=(associate)` when the associate contents have changed.
2+
3+
Fix #8856.
4+
5+
*Chris Thompson*
6+
17
* Abort a rake task when missing db/structure.sql like `db:schema:load` task.
28

39
*kennyj*

activerecord/lib/active_record/associations/has_one_association.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@ def replace(record, save = true)
2525
raise_on_type_mismatch!(record) if record
2626
load_target
2727

28-
# If target and record are nil, or target is equal to record,
29-
# we don't need to have transaction.
30-
if (target || record) && target != record
28+
return self.target if !(target || record)
29+
if (target != record) || record.changed?
3130
transaction_if(save) do
3231
remove_target!(options[:dependent]) if target && !target.destroyed?
3332

activerecord/test/cases/associations/has_one_associations_test.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,4 +522,20 @@ def test_has_one_transaction
522522
account = Account.find(2)
523523
assert_queries { company.account = account }
524524
end
525+
526+
def test_has_one_assignment_triggers_save_on_change
527+
pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?")
528+
ship = pirate.build_ship(name: 'old name')
529+
ship.save!
530+
531+
ship.name = 'new name'
532+
assert ship.changed?
533+
assert_queries(2) do
534+
# One query for updating name and second query for updating pirate_id
535+
pirate.ship = ship
536+
end
537+
538+
assert_equal 'new name', pirate.ship.reload.name
539+
end
540+
525541
end

0 commit comments

Comments
 (0)