Эта опция существует в ассоциации has_many, и она не задокументирована, но добрые люди из сообщества Rails предоставляют информацию о ней ниже в разделе комментариев. Так что, возможно, вы даже не знаете об этом варианте. И это здорово!

Но для тех, кто использует его в проекте или рассматривает возможность использования, напишу пару примеров, почему лучше этого не делать.

Предположим, у нас есть модели:

Выглядит чисто и аккуратно, но:

company = Company.first
user = User.first

# You'll see the raised error if you run:
company.users = []
company.users.destroy(user)

# No error but company doesn't have an association with the user anymore:
company.users.first.destroy
user.destroy

Еще хуже это работает с опцией through:

project = Project.first
user = User.first

# You'll see the raised error if you run:
project.users = []
project.users.destroy(user)

# No error:
project.tasks = []
project.tasks.first.destroy
Task.find(task_id).destroy
project.users.first.destroy
User.find(user_id).destroy

Кстати, вы можете насладиться спором о after_remove обратном вызове в обсуждении в репозитории Rails.

И если вы думаете, что after_destroy callback решит ваши проблемы, извините, что разочаровал вас, но будет обратная ситуация: все случаи будут работать, кроме project.users = [].

Поэтому я думаю, что это одна из многих причин избегать ада обратного вызова.