Update association callback docs

There is an old open issue (https://github.com/rails/rails/issues/14365)
saying that callbacks are not triggered when assocations are destroyed.

I believe the issue does not represent a bug, but maybe just a small
gap in the docs about triggering callbacks when removing associations.

This update changes the example of the section to use the `Firm` class.
so that we can include an `after_remove`. This also adds a small `Note:`
section reminding users on how to destory associations so that callbacks
are triggered.
This commit is contained in:
Nick Borromeo 2020-07-12 17:40:26 -07:00
parent ee95658b25
commit a44253323f
1 changed files with 28 additions and 8 deletions

View File

@ -594,19 +594,27 @@ module ActiveRecord
# you can also define callbacks that get triggered when you add an object to or remove an
# object from an association collection.
#
# class Project
# has_and_belongs_to_many :developers, after_add: :evaluate_velocity
# class Firm < ActiveRecord::Base
# has_many :clients,
# dependent: :destroy,
# after_add: :congratulate_client,
# after_remove: :log_after_remove
#
# def evaluate_velocity(developer)
# ...
# def congratulate_client(record)
# # ...
# end
#
# def log_after_remove(record)
# # ...
# end
# end
#
# It's possible to stack callbacks by passing them as an array. Example:
#
# class Project
# has_and_belongs_to_many :developers,
# after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
# class Firm < ActiveRecord::Base
# has_many :clients,
# dependent: :destroy,
# after_add: [:congratulate_client, -> (firm, record) { firm.log << "after_adding#{record.id}" }],
# after_remove: :log_after_remove
# end
#
# Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
@ -617,6 +625,18 @@ module ActiveRecord
# Similarly, if any of the +before_remove+ callbacks throw an exception, the object
# will not be removed from the collection.
#
# Note: To trigger remove callbacks, you must use +destroy+ / +destroy_all+ methods. For example:
#
# * <tt>firm.clients.destroy(client)</tt>
# * <tt>firm.clients.destroy(*clients)</tt>
# * <tt>firm.clients.destroy_all</tt>
#
# +delete+ / +delete_all+ methods like the following do *not* trigger remove callbacks:
#
# * <tt>firm.clients.delete(client)</tt>
# * <tt>firm.clients.delete(*clients)</tt>
# * <tt>firm.clients.delete_all</tt>
#
# == Association extensions
#
# The proxy objects that control the access to associations can be extended through anonymous