rails/rails — pull request #9346 by samdalton (2013-02-20 19:15:45+00:00)
Title: after_remove callbacks only run if record was removed.

If a record that does not belong to a HABTM collection is passed in to a collection to be deleted, the after_remove callback is run even though the record was not actually removed. This can cause unexpected behaviour, such as incorrectly decrementing a counter.

The new behaviour still has before_remove called, but after_remove called only if the record was actually removed from the collection.

Example of unexpected behaviour:
```ruby
class Post < ActiveRecord::Base
has_and_belongs_to_many :post_collections
end

class PostCollection < ActiveRecord::Base
has_and_belongs_to_many :posts, after_remove: :decrememnt_posts_count

def decrement_posts_count
PostCollection.decrement_counter :posts_count, self.id
end
end

post = Post.new
post_collection = PostCollection.new
post_collection.posts.delete(post)

# post_collection.posts_count is now -1
```

Addendum:
The pull request fixes behaviour that may or may not have been what was originally intended. If after_remove is to be called regardless of what happens to the data, this will invalidate the pull request. It seems intuitive however that the after_remove callback should only be run if the record was actually removed from the collection.