Tengo un objeto @foo con: has_many asociaciones a bar y quiero que antes de foo se destruyan todos los objetos de asociación de bar también se destruirán si {{X4} } tiene la propiedad type = test.

El siguiente código funciona y el objeto foo se elimina pero los bars siguen ahí: (si no uso la condición .where(type: "test), todos bars se eliminarán)

  def destroy
    @foo.bars.each{|b| b.update_attribute(:blub_id, nil)}
    @foo.bars.where(type: "test").destroy_all
    @foo.destroy
    respond_to do |format|
      format.html { redirect_to foo_url, notice: 'Foo was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
0
larz 13 ene. 2018 a las 03:12

3 respuestas

La mejor respuesta

Simplemente elimine @foo.bars.each{|b| b.update_attribute(:blub_id, nil)} y vuelva a intentarlo. Supuse que blub_id es una clave externa que indica a quién pertenece la barra actual.

Cuando hace que blub_id sea igual a nulo, los registros con un blub_id nulo no pertenece a nada y luego @foo.bars.where(type: "test").destroy_all no incluye estas barras.

1
Mahmoud Sayed 13 ene. 2018 a las 00:34

No sé si esa es una regla general o solo para esa acción del controlador, pero creo que sería mejor hacerlo en el modelo.

No sé qué es exactamente la línea

@foo.bars.each{|b| b.update_attribute(:blub_id, nil)}

Lo hace, pero si blub_id es la clave foránea, debe hacerlo DESPUÉS de destruir las barras con el tipo de prueba. En su modelo foo, puede hacerlo así:

before_destroy :destroy_test_bars

def destroy_test_bars
   self.bars.where(type: "test").destroy_all
   self.bars.update_all(blub_id: nil)
end

Luego, en su controlador, sería solo

  def destroy
    @foo.destroy
    respond_to do |format|
      format.html { redirect_to foo_url, notice: 'Foo was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

Piensa que podría funcionar. ¡Buena suerte!

3
Ronan Lopes 13 ene. 2018 a las 00:40

Una de las mejores maneras será agregar una devolución de llamada after_destroy donde pueda escribir la lógica que desee.

class Foo < ActiveRecord::Base
  has_many :bars
  after_destroy :cleanup

  private
  def cleanup
    if self.bars.where(type: "test")
      self.bars.destroy_all
    end
  end
end 
0
Ritesh Ranjan 13 ene. 2018 a las 02:39
48235720