O Rails tá lento? Reveja seu código…

27 de setembro de 2007  |  Ruby on Rails  | 

1339929731_4087ea7a65

Tenho um relacionamento muitos-para-um, e gostaria que ao excluir o objeto pai todos os seus relacionamentos (filhos) fossem também apagados no banco de dados. Esta exclusão automática existe e se chama exclusão em cascata. No Rails é muito simples implementar:

[source:ruby]
class Pai < ActiveRecord::Base
has_many :filhos, :dependent => true
end
[/source]

Esta declaração informa que o Filho não pode existir sem um Pai. Desta maneira, se eu apagar uma instância de Pai, todos os seus filhos também serão apagados. Mas, atenção, cada filho será apagado individualmente, será executado um DELETE para cada linha no banco de dados.

Mas se seus objetos Filhos forem exclusivos de um objeto Pai – e somente de um – então você pode trocar esta declaração por esta:

[source:ruby]
class Pai < ActiveRecord::Base
has_many :filhos, :exclusively_dependent => true
end
[/source]

Agora o Rails fará o mesmo, mas de uma vez, com apenas um comando SQL.

Fiquem atentos aos recursos do Rails, os maiores problemas de desempenho que encontro é em detalhes como esse.


9 Comentários


  1. Gustavo "Vatsu" Sales

    OI Carlos, tudo bom?

    Na verdade:

    :exclusively_dependent está em desuso, o melhor é usar:
    :dependent => :delete_all

    Cheers

  2. É, isso ae que o Gustavo falou!

    E outra dica para melhorar rendimento, é quando se tem relacionamentos, no find, tu usar o :include => {:model1, :model2, :model3 }
    Com isso ele faz inner join ao inves de fazer varias consultas…
    Mas tem que cuidar! :)

  3. Opa, em um sistema que estou desenvolvendo eu tinha usado a primeira opção, acompanhando os logs vi que ele gerava 1 sql para cada filho e acabei apagando na mão mesmo… (em rails significa 1 linha de código a mais :D)

    É bom saber dessa solução mais elegante, valeu pela dica!

  4. Bem lembrado Gustavo.

    Eu já tinha visto isto antes, mas acabei escrevendo da forma antiga no blog. Agora o correto é usar :dependent => :delete_all

    Para confirmar o que o Gustavo comentou o link é: http://dev.rubyonrails.org/ticket/6024 e http://dev.rubyonrails.org/attachment/ticket/6024/deprecation_warning_exclusively_dependent.diff

  5. Eles funcionariam em has_and_belongs_to_many também?

    Como exemplo vou dar Foto e Tag, com relacionamento muitos para muitos.

    Ao apagar todas as fotos de uma tag, essa tag deve ser apagada.
    Mas ao apagar apenas um foto, e ainda ter mais para aquela tag, essa nao deve ser apagada. Caso não tenha mais fotos para a tag, a tag também apaga.
    Seria melhor usar o :dependent => true?

  6. Gustavo "Vatsu" Sales

    XaXá,

    O has_and_belong_to_many não tem a opção :dependent

    Dá para sobrescrever o sql que deleta os registros,
    para agir como vc pretende com a opção :delete_sql

    Outra forma é fazer o overload do método destroy no model. Essa maneira me parece mais elegante.

    Cheers

  7. Ah sim, entendi.
    Muito obrigado pela ajuda!

  8. Ótimo post!!

    Pouca gente se lembra do exclusively_dependent na hora de criar seus models (eu estou nesta lista)!! Valeu pelo lembrete, vou anotar essa!!

    Felipe Giotto

  9. Felipe, fique esperto que o :exclusively_dependent vai mudar. Nos comentários tem as dicas.

    Abraço!

Trackbacks

  1. Coletânea de Links | Blog do Urubatan
  2. Alguns bits de tecnologia :D | Blog do Urubatan

Deixe um comentário