diff options
author | Sean Griffin <sean@seantheprogrammer.com> | 2018-02-26 11:16:10 -0700 |
---|---|---|
committer | Sean Griffin <sean@seantheprogrammer.com> | 2018-02-26 11:21:03 -0700 |
commit | 948b931925febac3c965ab13470065ced68f7b53 (patch) | |
tree | c6236159b8a1d1c061acf6541f775400fbc60bef | |
parent | 8a79d04e4dd7f0fc3c03fca905f86c03bc91ab11 (diff) | |
download | rails-948b931925febac3c965ab13470065ced68f7b53.tar.gz rails-948b931925febac3c965ab13470065ced68f7b53.tar.bz2 rails-948b931925febac3c965ab13470065ced68f7b53.zip |
Never attempt to write virtual attributes to the database
Currently the place where we limit what gets sent to the database is in
the implementation for `partial_writes`. We should also be restricting
it to column names when partial writes are turned off.
Note that we're using `&` instead of just defaulting to
`self.class.column_names`, as the instance version of `attribute_names`
does not include attributes which are uninitialized (were not included
in the select clause)
-rw-r--r-- | activerecord/lib/active_record/persistence.rb | 4 | ||||
-rw-r--r-- | activerecord/test/cases/dirty_test.rb | 19 |
2 files changed, 22 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 88b971327b..0b1000fcf9 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -703,7 +703,8 @@ 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) + def _update_record(attribute_names = self.column_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/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 14c4e3cbd4..d1a7366f5f 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -736,6 +736,25 @@ 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_predicate record, :non_persisted_attribute_changed? + 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!" |