2010-12-16 8 views
6

Acaba de aparecer un problema con un has_many: a través de la asociación y no se activan las devoluciones de llamada before/before-destroy.HMT collection_singular_ids = la eliminación de los modelos de unión es directa, no se activan las devoluciones de llamadas de destrucción

Digamos que tengo usuarios, grupos y una relación intermedia llamada membresía. Tengo un formulario que permite que los usuarios se inscriban en grupos al crear un nuevo registro de membresía cuando marcan casillas de verificación asociadas. Básicamente una matriz de group_ids.

es como la siguiente:

Which group would you like to join? (check all that apply) 
[] Group A 
[] Group B 
[] Group C 

Y Deseo expresar acciones tales como unirse a un grupo o salir de un grupo de tabla de registro de actividad y hacer algunas otras thigns menos importantes.

Tengo el siguiente definido:

class Group < AR::Base 
    has_many :memberships 
    has_many :users, :through => :memberships 
end 

class Membership < AR::Base 
    belongs_to :user 
    belongs_to :group 

    after_create :log_event_to_audit_table 
    after_destroy :log_event_to_audit_table 

end 

class User < ActiveRecord::Base 
    has_many :memberships 
    has_many :groups, :through => :memberships 

    attr_accessible :group_ids # enables mass-assignment 
end 

Cuando un nuevo registro de afiliación se crea el after_create se ejecuta como se esperaba. Sin embargo, el after_destroy no se activa.

después de que Google-ción y leer los documentos que he descubierto la razón por la cual:

"Borrado automático de unirse a los modelos es directa, sin destruyen las devoluciones de llamada se activan " - de las guías de Ruby.

Hmmmmmm ...

Así que la unión del modelo (en este caso de afiliación) destruyen las devoluciones de llamada no se activan. Bueno, eso es una decepción. ¿Alguna razón de por qué?

Entonces, ¿cuál es la mejor forma de evitar este problema? ¿Debo definir mi propio método membership_ids = en el modelo de usuario que llama membership.destroy directamente?

Abierto a cualquier sugerencia sobre las mejores prácticas en tal escenario.

Gracias!

Respuesta

9

Después de examinar cuidadosamente documentos de la API, resulta has_many y HABTM tienen algunas opciones sólo para este caso:

before_add, after_add, before_remove y after_remove

class User < ActiveRecord::Base 
    has_many :groups, :through => :memberships, :after_remove => :your_custom_method 
end 

A juzgar por cuántas respuestas que obtuve, esto no debe ser una característica muy bien documentada/utilizada.

Solo anotándolo aquí para mí y para otros que pueden tropezar como yo.

+0

Esto es una locura ... muchas gracias a usted.Estuve luchando con esto por mucho tiempo. –

+0

Esta parece ser la forma de Rails para hacerlo. Aún así, creo que la acción desencadenada después de eliminar un 'grupo' * debería * ser parte del modelo' membresía' porque la eliminación de un 'grupo' del' usuario' es en realidad una eliminación de una 'membresía'. Lástima, Rails no permite eso sin soluciones sucias. –

-1

he luchado con el mismo problema hace poco y lo resolvió mediante la extensión de asociación y anulando su método de eliminación:

class User < ActiveRecord::Base 
    has_many :memberships 
    has_many :groups, :through => :memberships do 
    def delete(*args) 
     groups = args.flatten 
     # destroy memberships in order to trigger their callbacks: 
     proxy_association.owner.memberships.where(group_id: groups).destroy_all 
     super 
    end 
    end 
    ... 
end 

Como nota al margen, parece que no podemos depender de forma fiable en devoluciones de llamada modelo en Rails, que es un poco decepcionante.

Cuestiones relacionadas