Об уничтожении ресурса, который я хочу сохранить, я хочу гарантировать несколько вещей, прежде чем я разрешу операцию уничтожения продолжить? В принципе, я хочу, чтобы остановить операцию уничтожения, если я заметил, что это приведет к тому, что база данных окажется недопустимой? Нет никаких обратных вызовов проверки на операцию уничтожения, поэтому как можно «подтвердить», следует ли принять операцию уничтожения?Как «проверять» на уничтожение в рельсах
ответ
Вы можете создать исключение, которое вы затем поймаете. Rails wraps удаляет транзакции, что помогает.
Например:
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
В качестве альтернативы вы можете использовать before_destroy обратного вызова. Этот обратный вызов обычно используется для уничтожения зависимых записей, но вы можете исключить исключение или добавить ошибку.
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
теперь будет возвращать ложь, и myBooking.errors
будет заполняться по возвращении.
Гм, что случилось с просто проверить ассоциацию booking_payments, которая должна быть определена на этой модели вместо вызова BookingPayment .count, приводящий к уродливому коду? – 2008-09-24 00:37:25
Я отредактировал свой ответ соответственно. Извините, я вытащил это из какого-то старого кода ... – 2008-09-24 18:26:27
Обратите внимание, что там, где теперь говорится «... ОК, идите вперед и уничтожьте», вам нужно поставить «супер», поэтому на самом деле вызывается метод первоначального уничтожения. – 2009-08-19 15:13:02
Вы также можете использовать обратный вызов before_destroy для повышения исключения.
В ассоциациях ActiveRecord has_many и has_one разрешает зависимую опцию, которая гарантирует удаление связанных строк таблицы при удалении, но обычно это означает, что ваша база данных чиста, а не предотвращает ее недействительность.
Вы можете обернуть разрушающего действия в "если" заявление в контроллере:
def destroy # in controller context
if (model.valid_destroy?)
model.destroy # if in model context, use `super`
end
end
Где valid_destroy? - это метод класса модели, который возвращает true, если выполнены условия для уничтожения записи.
Наличие такого способа также позволит вам предотвратить отображение пользователем опции удаления, что улучшит работу пользователя, так как пользователь не сможет выполнить незаконную операцию.
просто примечание:
Для рельсов 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
Я закончил с использованием кода здесь, чтобы создать can_destroy переопределение на 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
Это Добавленная преимущество сделать тривиальным, чтобы скрыть/показать кнопку удаления на ui
У меня есть эти классы или модели
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
Теперь при удалении предприятия этот процесс проверяет, есть ли продукты, связанные с предприятиями Примечание: Вы должны написать это в верхней части класса для того, чтобы подтвердить его первый.
Это то, что я сделал с 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
Использование ActiveRecord контекст проверки в 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
Связанный: http://stackoverflow.com/questions/5520320/validate-before-destroy – 2011-11-08 16:31:22