tengo estos modelos

1 
2 
3 
4
class User < ActiveRecord::Base
  has_many :user_functions, :dependent => :destroy
  has_many :functions, :through => :user_functions
  accepts_nested_attributes_for :functions, allow_destroy: true

Modelo de la tabla vinculada:

1 
2 
3 
4 
5
class UserFunction < ActiveRecord::Base
  belongs_to :user, inverse_of: :user_functions
  belongs_to :function, inverse_of: :user_functions
  after_destroy :unplan_items
  after_create :plan_items

y por supuesto el modelo de función pero esto es como usuario…

Ahora cuando hago lo siguiente en mis pruebas:

1 
2 
3 
4 
5
@user.functions = [@functions]
@user.save
expect(@user.planned_items.count).to eq(1)
@user.functions = []
@user.save

Me doy cuenta de que la devolución de llamada after_destroy no se llama. ¿Por qué es esto y cómo puedo evitarlo? Hay ciertos pasos que deben realizarse cada vez que se destruye una UserFunction...

Creo que esto tiene que ver con: https://github.com/rails/rails/issues/7618 (aunque estoy usando Rails 4.2.5). El after_create está funcionando perfectamente sin embargo...

Actualmente, Rails usa :delete_all como estrategia predeterminada de has_many_through. Solo llama :destroy_allcuando especificamos explícitamente dependent: :destroyen la asociación.

Los documentos mencionan consejos para usar has_many :throughsi necesita devoluciones de llamada:
vea la sugerencia aquí: http://guides.rubyonrails.org/association_basics.html

Debe usar has_many :through si necesita validaciones, devoluciones de llamada
o atributos adicionales en el modelo de combinación.

Entonces, actualmente hay una inconsistencia entre after_createcuál hace la devolución de llamada y after_destroy.

Esto se menciona en estos dos números publicados en GitHub:

https://github.com/rails/rails/issues/7618

https://github.com/rails/rails/issues/27099

La solución por ahora es poner explícitamente :dependent => :destroyla :throughparte. Esto asegurará que se utilice la devolución de llamada.

1 
2 
3 
4
class User < ActiveRecord::Base
  has_many :user_functions
  has_many :functions, :through => :user_functions, :dependent => :destroy
  accepts_nested_attributes_for :functions, allow_destroy: true

Para cualquiera que lea este 2021+

Cambia esto

1 
2
has_many :object_tags, :as => :taggable, :dependent => :destroy
has_many :tags, :through => :object_tags

A esto

1 
2
has_many :object_tags
has_many :tags, :through => :object_tags, :dependent => :destroy