diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2017-04-02 08:24:23 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2017-04-21 07:20:52 +0900 |
commit | c0038f7c362fa0c92fc9e1ea3bdb2706f42386c6 (patch) | |
tree | 0713cb06b1f2be74776d0b52c88ac89b2e3acbf8 /activerecord/lib/active_record/persistence.rb | |
parent | 972df059bbedfe60d29caa8a561f5aff76883e63 (diff) | |
download | rails-c0038f7c362fa0c92fc9e1ea3bdb2706f42386c6.tar.gz rails-c0038f7c362fa0c92fc9e1ea3bdb2706f42386c6.tar.bz2 rails-c0038f7c362fa0c92fc9e1ea3bdb2706f42386c6.zip |
Prevent double firing the before save callback of new object when the parent association saved in the callback
Related #18155, #26661, 268a5bb, #27434, #27442, and #28599.
Originally #18155 was introduced for preventing double insertion caused
by the after save callback. But it was caused the before save issue
(#26661). 268a5bb fixed #26661, but it was caused the performance
regression (#27434). #27442 added new record to `target` before calling
callbacks for fixing #27434. But it was caused double firing before save
callback (#28599). We cannot add new object to `target` before saving
the object.
This is improving #18155 to only track callbacks after `save`.
Fixes #28599.
Diffstat (limited to 'activerecord/lib/active_record/persistence.rb')
-rw-r--r-- | activerecord/lib/active_record/persistence.rb | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 7ceb7d1a55..f652c7c3a1 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -100,6 +100,10 @@ module ActiveRecord !(@new_record || @destroyed) end + ## + # :call-seq: + # save(*args) + # # Saves the model. # # If the model is new, a record gets created in the database, otherwise @@ -121,12 +125,16 @@ module ActiveRecord # # Attributes marked as readonly are silently ignored if the record is # being updated. - def save(*args) - create_or_update(*args) + def save(*args, &block) + create_or_update(*args, &block) rescue ActiveRecord::RecordInvalid false end + ## + # :call-seq: + # save!(*args) + # # Saves the model. # # If the model is new, a record gets created in the database, otherwise @@ -150,8 +158,8 @@ module ActiveRecord # being updated. # # Unless an error is raised, returns true. - def save!(*args) - create_or_update(*args) || raise(RecordNotSaved.new("Failed to save the record", self)) + def save!(*args, &block) + create_or_update(*args, &block) || raise(RecordNotSaved.new("Failed to save the record", self)) end # Deletes the record in the database and freezes this instance to @@ -550,9 +558,9 @@ module ActiveRecord self.class.unscoped.where(self.class.primary_key => id) end - def create_or_update(*args) + def create_or_update(*args, &block) _raise_readonly_record_error if readonly? - result = new_record? ? _create_record : _update_record(*args) + result = new_record? ? _create_record(&block) : _update_record(*args, &block) result != false end @@ -567,6 +575,9 @@ module ActiveRecord rows_affected = self.class.unscoped._update_record attributes_values, id, id_in_database @_trigger_update_callback = rows_affected > 0 end + + yield(self) if block_given? + rows_affected end @@ -579,6 +590,9 @@ module ActiveRecord self.id ||= new_id if self.class.primary_key @new_record = false + + yield(self) if block_given? + id end |