2012-07-01 3 views
4

У меня есть модель с «членом», «группой», «членством» и «пользователем». Данные организованы в древовидной структуре с группами, которые связаны с ними членами. Члены без каких-либо групповых ассоциаций считаются сиротами и бесполезны для приложения.Предотвращение осиротевших объектов, с has_many через ассоциации, в Rails 3

Когда пользователь уничтожает группу, не должно быть никаких сиротских членов. Другими словами: член должен быть уничтожен, если и только если последняя групповая ассоциация удалена. Предпочтительно это должно происходить в одной транзакции, но наиболее важным аспектом является то, что потерянный объект не накапливается в базе данных с течением времени.

Необходимо удалить только те члены и группы, которые связаны с пользователем. Группы, члены и члены, принадлежащие другим пользователям, не должны быть затронуты вообще. (Можно было бы утверждать, что глобальный метод очистки можно запускать в любое время, но я хочу изолировать деструктивные операции, чтобы воздействовать только на текущие объекты пользователей.)

Мой вопрос: что является самым эффективным и элегантным способом реализации этой функции в Rails 3? Моя текущая реализация, проиллюстрированная упрощенной моделью, описанной здесь, не удаляет члена из базы данных, если пользователь не удалит ее вручную (или что весь пользователь и все его данные удалены путем удаления каскада.)

class User < ActiveRecord::Base 
    has_many :groups, :foreign_key => 'owner_id', :dependent => :delete_all 
    has_many :members, :foreign_key => 'owner_id', :dependent => :destroy 
end 

class Member < ActiveRecord::Base 
    belongs_to :owner, :class_name => 'User'  
    has_many :memberships, :dependent => :destroy 
    has_many :groups, :through => :memberships 
end 

class Membership < ActiveRecord::Base 
    belongs_to :member 
    belongs_to :group 
end 

class Group < ActiveRecord::Base 
    belongs_to :owner, :class_name => 'User' 
    belongs_to :parent, :class_name => 'Group'  
    has_many :groups, :foreign_key => 'parent_id', :dependent => :destroy 
    has_many :memberships, :dependent => :destroy 
    has_many :members, :through => :memberships 
end 

ответ

8

Я решил это, добавив обратный вызов в классе Membership, который уведомляет участника, когда членство уничтожено. Затем объект-член уничтожает себя, если у него больше нет групповых ассоциаций.

class Membership < ActiveRecord::Base 
    belongs_to :member 
    belongs_to :group 

    after_destroy :notify_member 

    def notify_member 
    member.destroy_if_empty_groups 
    end 
end 

class Member < ActiveRecord::Base 
    belongs_to :owner, :class_name => 'User'  
    has_many :memberships, :dependent => :destroy 
    has_many :groups, :through => :memberships 

    def destroy_if_empty_groups 
    if groups.count == 0 
     self.destroy 
    end 
    end 
end 
+1

Стоит отметить: это не будет работать с 'has_and_belongs_to_many' ассоциации в качестве модели вызывающей' after_destroy' больше не будет иметь 'id' и не будет в состоянии определить, какие объекты она используется ассоциироваться с. –

Смежные вопросы