Pergunta

Em destruição de um recurso repousante, quero garantir algumas coisas antes de eu permitir que uma operação de destruir continuar? Basicamente, eu quero a capacidade de parar a operação de destruir se eu notar que isso iria colocar o banco de dados em um estado inválido? Não há retornos de chamada de validação em uma operação de destruir, Assim como um "validar" se uma operação de destruir deve ser aceito?

Foi útil?

Solução

Você pode gerar uma exceção que você então pegar. Trilhos envoltórios exclusões em uma transação, o que ajuda matérias.

Por exemplo:

class Booking < ActiveRecord::Base
  has_many   :booking_payments
  ....
  def destroy
    raise "Cannot delete booking with payments" unless booking_payments.count == 0
    # ... ok, go ahead and destroy
    super
  end
end

Como alternativa, você pode usar o callback before_destroy. Este retorno é normalmente usado para destruir registros dependentes, mas você pode lançar uma exceção ou adicionar um erro em seu lugar.

def before_destroy
  return true if booking_payments.count == 0
  errors.add :base, "Cannot delete booking with payments"
  # or errors.add_to_base in Rails 2
  false
  # Rails 5
  throw(:abort)
end

myBooking.destroy agora irá retornar falso, e myBooking.errors será preenchida no retorno.

Outras dicas

apenas uma nota:

Para Rails 3

class Booking < ActiveRecord::Base

before_destroy :booking_with_payments?

private

def booking_with_payments?
        errors.add(:base, "Cannot delete booking with payments") unless booking_payments.count == 0

        errors.blank? #return false, to not destroy the element, otherwise, it will delete.
end

É o que eu fiz com Rails 5:

before_destroy do
  cannot_delete_with_qrcodes
  throw(:abort) if errors.present?
end

def cannot_delete_with_qrcodes
  errors.add(:base, 'Cannot delete shop with qrcodes') if qrcodes.any?
end

O ActiveRecord associações has_many e has_one permite uma opção dependente que vai fazer linhas da tabela certeza relacionados são eliminados na exclusão, mas isso geralmente é para manter seu banco de dados limpo em vez de impedi-la de ser inválido.

Você pode envolver a ação destruir em um "if" no controlador:

def destroy # in controller context
  if (model.valid_destroy?)
    model.destroy # if in model context, use `super`
  end
end

Onde valid_destroy? é um método em sua classe de modelo que retorna verdadeiro se estão reunidas as condições para a destruição de um registro.

Ter um método como este também irá permitir que você evitar a exibição da opção de exclusão para o usuário - o que irá melhorar a experiência do usuário como o usuário não será capaz de executar uma operação ilegal.

Acabei usando código daqui para criar uma substituição can_destroy em activerecord: https://gist.github.com/andhapp/1761098

class ActiveRecord::Base
  def can_destroy?
    self.class.reflect_on_all_associations.all? do |assoc|
      assoc.options[:dependent] != :restrict || (assoc.macro == :has_one && self.send(assoc.name).nil?) || (assoc.macro == :has_many && self.send(assoc.name).empty?)
    end
  end
end

Este tem a vantagem de tornar mais trivial para ocultar / mostrar um botão delete no ui

Você também pode usar o callback before_destroy para levantar uma exceção.

Eu tenho essas classes ou modelos

class Enterprise < AR::Base
   has_many :products
   before_destroy :enterprise_with_products?

   private

   def empresas_with_portafolios?
      self.portafolios.empty?  
   end
end

class Product < AR::Base
   belongs_to :enterprises
end

Agora, quando você excluir uma empresa este processo valida se há produtos associados a empresas Nota:. Você tem que escrever isso no topo da classe, a fim de validar primeiro

Use ActiveRecord validação contexto em Rails 5.

class ApplicationRecord < ActiveRecord::Base
  before_destroy do
    throw :abort if invalid?(:destroy)
  end
end
class Ticket < ApplicationRecord
  validate :validate_expires_on, on: :destroy

  def validate_expires_on
    errors.add :expires_on if expires_on > Time.now
  end
end

Eu estava esperando que esta seria apoiada por isso abri uma trilhos problema para obter acrescentou:

https://github.com/rails/rails/issues/32376

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top