Diferença entre Destruir e Excluir


210

Qual é a diferença entre

@model.destroy e @model.delete

Por exemplo:

Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all

Realmente importa se eu uso um ou outro?

Respostas:


289

Basicamente, destroyexecuta quaisquer retornos de chamada no modelo enquanto deletenão.

Na API do Rails :

  • ActiveRecord::Persistence.delete

    Exclui o registro no banco de dados e congela esta instância para refletir que nenhuma alteração deve ser feita (pois não pode ser persistida). Retorna a instância congelada.

    A linha é simplesmente removida com uma instrução SQL DELETE na chave primária do registro e nenhum retorno de chamada é executado.

    Para impor os retornos de chamada before_destroy e after_destroy do objeto ou qualquer outra opção de associação dependente, use #destroy.

  • ActiveRecord::Persistence.destroy

    Exclui o registro no banco de dados e congela esta instância para refletir que nenhuma alteração deve ser feita (pois não pode ser persistida).

    Há uma série de retornos de chamada associados à destruição. Se o retorno de chamada before_destroy retornar false, a ação será cancelada e destroy retornará false. Consulte ActiveRecord :: Callbacks para obter mais detalhes.


Olá @ user740584 - obrigado pela sua resposta. O que você quer dizer com "executa retornos de chamada no modelo"?
BKSpurgeon

3
@BKSpurgeon, ele quer dizer ActiveRecord :: Callbacks: api.rubyonrails.org/classes/ActiveRecord/Callbacks.html . Um desses retornos de chamada é o model#before_destroyque pode ser usado para interromper a destroy()chamada final sob certas condições.
Todd

102

delete excluirá apenas o registro de objeto atual do db, mas não os registros filhos associados do db.

destroy excluirá o registro de objeto atual do db e também o registro filho associado do db.

Seu uso realmente importa:

Se seus vários objetos pai compartilharem objetos filhos comuns, a chamada destroyde um objeto pai específico excluirá objetos filhos que são compartilhados entre outros pais múltiplos.


5
Resposta brilhante. obrigado. eu acrescentaria que a terminologia que eu entendo é que as crianças são "mortas". infanticídio brutal.
BKSpurgeon

Na maioria dos casos em produção, você deseja usar 'destroy'
Outside_Box 27/10/16

Não, isso não é necessário.
Taimoor Changaiz 27/10

Eu acho que a palavra que você deve usar destroyé descendente , não filhos : de acordo com a documentação, destroy "cria um novo objeto a partir dos atributos e depois chama destrua nele". rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

Quando você invoca destroyou destroy_allem um ActiveRecordobjeto, o ActiveRecordprocesso de 'destruição' é iniciado, ele analisa a classe que você está excluindo, determina o que deve fazer por dependências, executa validações etc.

Quando você invoca deleteou delete_allem um objeto, ActiveRecordapenas tenta executar a DELETE FROM tablename WHERE conditionsconsulta no banco de dados, não executando outras ActiveRecordtarefas de nível superior.


4

Sim, existe uma grande diferença entre os dois métodos. Use delete_all se desejar que os registros sejam excluídos rapidamente, sem que os retornos de chamada do modelo sejam chamados.

Se você se preocupa com os retornos de chamada dos seus modelos, use destroy_all

Dos documentos oficiais

http://apidock.com/rails/ActiveRecord/Base/destroy_all/class

destroy_all (conditions = nil) public

Destrói as condições de correspondência dos registros instanciando cada registro e chamando seu método de destruição. Os retornos de chamada de cada objeto são executados (incluindo: opções de associação dependentes e métodos de observação before_destroy / after_destroy Observer). Retorna a coleção de objetos que foram destruídos; cada um será congelado, para refletir que nenhuma alteração deve ser feita (pois não pode ser persistida).

Nota: A instanciação, execução de retorno de chamada e exclusão de cada registro podem ser demoradas quando você está removendo muitos registros de uma só vez. Ele gera pelo menos uma consulta SQL DELETE por registro (ou possivelmente mais, para impor seus retornos de chamada). Se você deseja excluir muitas linhas rapidamente, sem se preocupar com suas associações ou retornos de chamada, use delete_all.


2

Basicamente, "excluir" envia uma consulta diretamente ao banco de dados para excluir o registro. Nesse caso, o Rails não sabe quais atributos estão no registro e está excluindo nem se há retornos de chamada (como before_destroy).

O método "destroy" pega o ID passado, busca o modelo no banco de dados usando o método "find" e, em seguida, chama destroy nele. Isso significa que os retornos de chamada são acionados.

Você deseja usar "excluir" se não desejar que os retornos de chamada sejam acionados ou se desejar um melhor desempenho. Caso contrário (e na maioria das vezes), você desejará usar "destroy".


2

Muitas respostas já; queria pular um pouco mais.

docs :

Para has_many, destroy e destroy_all sempre chamará o método de destruição dos registros removidos, para que os retornos de chamada sejam executados. No entanto, delete e delete_all farão a exclusão de acordo com a estratégia especificada pela opção: dependente ou, se nenhuma opção for dependente for fornecida, seguirá a estratégia padrão. A estratégia padrão é não fazer nada (deixe as chaves estrangeiras com os IDs principais configurados), exceto has_many: through, em que a estratégia padrão é delete_all (exclua os registros de junção, sem executar seus retornos de chamada).

O deleteverbage funciona de maneira diferente para ActiveRecord::Association.has_manye ActiveRecord::Base. No último, a exclusão executará SQL DELETEe ignorará todas as validações / retornos de chamada. O primeiro será executado com base na :dependentopção passada para a associação. No entanto, durante o teste, encontrei o seguinte efeito colateral no qual os retornos de chamada eram executados apenas deletee nãodelete_all

dependent: :destroy Exemplo:

class Parent < ApplicationRecord
   has_many :children,
     before_remove: -> (_) { puts "before_remove callback" },
     dependent: :destroy
end

class Child < ApplicationRecord
   belongs_to :parent

   before_destroy -> { puts "before_destroy callback" }
end

> child.delete                            # Ran without callbacks
Child Destroy (99.6ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 21]]

> parent.children.delete(other_child)     # Ran with callbacks
before_remove callback
before_destroy callback
Child Destroy (0.4ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 22]]

> parent.children.delete_all              # Ran without callbacks
Child Destroy (1.0ms)  DELETE FROM "children" WHERE "children"."parent_id" = $1  [["parent_id", 1]]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.