2012-01-25 4 views
2

я следующие классы/отношения определены:Рубин на Rails: Лучше подход для удаления связанных моделей

class Component < ActiveRecord::Base 
    has_many :component_stories,:dependent => :destroy 
    has_many :stories, :through => :component_stories 
end 

class Story < ActiveRecord:Base 
    has_many :component_stories,:dependent => :destroy 
    has_many :components, :through => :component_stories 
end 

class ComponentStory < ActiveRecord::Base 
    belongs_to :component 
    belongs_to :story 
end 

Допустим, мы COMPONENT1 с 2 историй: story1 и story2. story2 также принадлежит компоненту2. Если мы удалим компонент1, история1 будет удалена навсегда, но story2 останется, поскольку он принадлежит компоненту2. Я определил метод в компонентной модели для удаления истории, не связанную с каким-либо другим компонентом:

def delete_dependent_stories 
    stories.each do |story| 
    if story.component_stories.size == 1 
     story.destroy 
    end 
    end 
end 

Этот метод будет вызван в разрушить действия для components_controller:

def destroy 
    component = Component.find(params[:id]) 
    component.delete_dependent_stories 
    component.destroy 
    ... 
end 

Таким образом, я делаю конечно, нет «зомбических» историй, не связанных с каким-либо компонентом. Моя забота заключается в том, может ли быть лучший подход, который заменяет этот метод в модели Component.

+0

выглядит отлично - я бы просто переместить метод delete_dependent_stories к before_destroy обратного вызова в компонентной модели – klochner

+0

'если story.component_stories.size == 1 story.destroy end' не будет корректно работать в параллельной среде. Рассмотрим ситуацию, когда у нас есть история с двумя компонентами c1 и c2, и два пользователя одновременно удаляют эти компоненты. В этом случае оператор 'if' возвращает false (потому что' story.component_storues.size' на самом деле равен 2), никто не удаляет эту историю, и - voilà - у вас есть зомби. – DNNX

+0

BTW, аналогичный вопрос: http://stackoverflow.com/questions/5546001/ruby-on-rails-3-after-destroy-method-to-destroy-object-if-there-is-no-more-rela – DNNX

ответ

0

Вы должны использовать модель обратных вызовов, как это:

class Component < ActiveRecord::Base 
    has_many :component_stories,:dependent => :destroy 
    has_many :stories, :through => :component_stories 

    after_destroy :delete_dependent_story? 

    private 

    def delete_dependent_stories 
    stories.each do |story| 
     if story.has_component_stories? 
     story.destroy 
     end 
    end 
end 

class Story < ActiveRecord:Base 
    has_many :component_stories,:dependent => :destroy 
    has_many :components, :through => :component_stories 

    self.has_component_story? 
    component_stories.size == 1 
    end 
end 

Не используйте before_destroy, как это устранило бы story независимо от успеха делеции component.