Skip to content

Commit d3f4db9

Browse files
authored
Merge pull request rails#42355 from Shopify/split-partial-writes
Deprecate `partial_writes` in favor of `partial_inserts` and `partial_updates`
2 parents 90fe5ad + 125987e commit d3f4db9

File tree

7 files changed

+57
-15
lines changed

7 files changed

+57
-15
lines changed

activerecord/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Deprecate `partial_writes` in favor of `partial_inserts` and `partial_updates`.
2+
3+
This allows to have a different behavior on update and create.
4+
5+
*Jean Boussier*
6+
17
* Fix compatibility with `psych >= 4`.
28

39
Starting in Psych 4.0.0 `YAML.load` behaves like `YAML.safe_load`. To preserve compatibility

activerecord/lib/active_record/attribute_methods/dirty.rb

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ module Dirty
1414
raise "You cannot include Dirty after Timestamp"
1515
end
1616

17-
class_attribute :partial_writes, instance_writer: false, default: true
17+
class_attribute :partial_updates, instance_writer: false, default: true
18+
class_attribute :partial_inserts, instance_writer: false, default: true
1819

1920
# Attribute methods for "changed in last call to save?"
2021
attribute_method_affix(prefix: "saved_change_to_", suffix: "?", parameters: "**options")
@@ -26,6 +27,32 @@ module Dirty
2627
attribute_method_suffix("_change_to_be_saved", "_in_database", parameters: false)
2728
end
2829

30+
module ClassMethods
31+
def partial_writes
32+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
33+
ActiveRecord::Base.partial_writes is deprecated and will be removed in Rails 7.1.
34+
Use `partial_updates` and `partial_inserts` instead.
35+
MSG
36+
partial_updates && partial_inserts
37+
end
38+
39+
def partial_writes?
40+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
41+
`ActiveRecord::Base.partial_writes?` is deprecated and will be removed in Rails 7.1.
42+
Use `partial_updates?` and `partial_inserts?` instead.
43+
MSG
44+
partial_updates? && partial_inserts?
45+
end
46+
47+
def partial_writes=(value)
48+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
49+
`ActiveRecord::Base.partial_writes=` is deprecated and will be removed in Rails 7.1.
50+
Use `partial_updates=` and `partial_inserts=` instead.
51+
MSG
52+
self.partial_updates = self.partial_inserts = value
53+
end
54+
end
55+
2956
# <tt>reload</tt> the record and clears changed attributes.
3057
def reload(*)
3158
super.tap do
@@ -185,20 +212,24 @@ def _touch_row(attribute_names, time)
185212
@_touch_attr_names, @_skip_dirty_tracking = nil, nil
186213
end
187214

188-
def _update_record(attribute_names = attribute_names_for_partial_writes)
215+
def _update_record(attribute_names = attribute_names_for_partial_updates)
189216
affected_rows = super
190217
changes_applied
191218
affected_rows
192219
end
193220

194-
def _create_record(attribute_names = attribute_names_for_partial_writes)
221+
def _create_record(attribute_names = attribute_names_for_partial_inserts)
195222
id = super
196223
changes_applied
197224
id
198225
end
199226

200-
def attribute_names_for_partial_writes
201-
partial_writes? ? changed_attribute_names_to_save : attribute_names
227+
def attribute_names_for_partial_updates
228+
partial_updates? ? changed_attribute_names_to_save : attribute_names
229+
end
230+
231+
def attribute_names_for_partial_inserts
232+
partial_inserts? ? changed_attribute_names_to_save : attribute_names
202233
end
203234
end
204235
end

activerecord/lib/active_record/timestamp.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def create_or_update(touch: true, **)
127127
end
128128

129129
def should_record_timestamps?
130-
record_timestamps && (!partial_writes? || has_changes_to_save?)
130+
record_timestamps && (!partial_updates? || has_changes_to_save?)
131131
end
132132

133133
def timestamp_attributes_for_create_in_model

activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,15 +1007,15 @@ def test_association_name_is_the_same_as_join_table_name
10071007
assert_nothing_raised { user.jobs_pool.clear }
10081008
end
10091009

1010-
def test_has_and_belongs_to_many_while_partial_writes_false
1011-
original_partial_writes = ActiveRecord::Base.partial_writes
1012-
ActiveRecord::Base.partial_writes = false
1010+
def test_has_and_belongs_to_many_while_partial_inserts_false
1011+
original_partial_inserts = ActiveRecord::Base.partial_inserts
1012+
ActiveRecord::Base.partial_inserts = false
10131013
developer = Developer.new(name: "Mehmet Emin İNAÇ")
10141014
developer.projects << Project.new(name: "Bounty")
10151015

10161016
assert developer.save
10171017
ensure
1018-
ActiveRecord::Base.partial_writes = original_partial_writes
1018+
ActiveRecord::Base.partial_inserts = original_partial_inserts
10191019
end
10201020

10211021
def test_has_and_belongs_to_many_with_belongs_to

activerecord/test/cases/autosave_association_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ def test_not_resaved_when_unchanged
267267

268268
firm = Firm.first
269269
firm.account = Account.first
270-
assert_queries(Firm.partial_writes? ? 0 : 1) { firm.save! }
270+
assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! }
271271

272272
firm = Firm.first.dup
273273
firm.account = Account.first

activerecord/test/cases/dirty_test.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -943,11 +943,14 @@ def check_around
943943

944944
private
945945
def with_partial_writes(klass, on = true)
946-
old = klass.partial_writes?
947-
klass.partial_writes = on
946+
old_inserts = klass.partial_inserts?
947+
old_updates = klass.partial_updates?
948+
klass.partial_inserts = on
949+
klass.partial_updates = on
948950
yield
949951
ensure
950-
klass.partial_writes = old
952+
klass.partial_inserts = old_inserts
953+
klass.partial_updates = old_updates
951954
end
952955

953956
def check_pirate_after_save_failure(pirate)

guides/source/configuring.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,9 @@ in controllers and views. This defaults to `false`.
416416
417417
* `config.active_record.record_timestamps` is a boolean value which controls whether or not timestamping of `create` and `update` operations on a model occur. The default value is `true`.
418418
419-
* `config.active_record.partial_writes` is a boolean value and controls whether or not partial writes are used (i.e. whether updates only set attributes that are dirty). Note that when using partial writes, you should also use optimistic locking `config.active_record.lock_optimistically` since concurrent updates may write attributes based on a possibly stale read state. The default value is `true`.
419+
* `config.active_record.partial_inserts` is a boolean value and controls whether or not partial writes are used when creating new records (i.e. whether inserts only set attributes that are different from the default). The default value is `true`.
420+
421+
* `config.active_record.partial_updates` is a boolean value and controls whether or not partial writes are used when updating existing records (i.e. whether updates only set attributes that are dirty). Note that when using partial updates, you should also use optimistic locking `config.active_record.lock_optimistically` since concurrent updates may write attributes based on a possibly stale read state. The default value is `true`.
420422
421423
* `config.active_record.maintain_test_schema` is a boolean value which controls whether Active Record should try to keep your test database schema up-to-date with `db/schema.rb` (or `db/structure.sql`) when you run your tests. The default is `true`.
422424

0 commit comments

Comments
 (0)