Rails:如何防止删除记录?

时间:2016-09-01 20:31:19

标签: ruby-on-rails ruby-on-rails-4

我有一个模型国家,因此有一个表国家。国家/地区表作为iso国家和货币代码的集合,不应该减少内容(在我填写种子数据之后)。因为Country是ActiveRecord :: Base的子类,所以它继承了删除记录的类方法,如destroy,delete_all等。我正在寻找一种解决方案,以防止删除模型级别的记录

OFC。我知道我可以通过覆盖这些方法来利用面向对象的方法来解决这个问题(并在调用时引发错误),但这假设我必须知道基类的所有继承方法。如果有人能提供更优雅的解决方案,我会很高兴。

3 个答案:

答案 0 :(得分:1)

有一个before_destroy回调,也许你可以利用它。

before_destroy :stop_destroy

def stop_destroy
  self.errors[:base] << "Countries cannot be deleted"
  return false
end

答案 1 :(得分:1)

从Mark Swardstrom的答案中汲取灵感,我提出以下建议也适用于Rails> 5.0:

在您的模型内:

before_destroy :stop_destroy

def stop_destroy
  errors.add(:base, :undestroyable)
  throw :abort
end

以下内容将使对model.destroy的所有调用均返回false,并且不会删除您的模型。

您可以说仍然可以使用model.delete的调用,并删除您的记录,但是由于这些调用是较低级别的调用,因此对我来说非常有意义。

您也可以根据需要直接从数据库中删除记录,但是上述解决方案可以防止从应用程序级别删除,这是检查的正确位置。

Rubocop检查您对delete或delete_all的呼叫并发出警告,因此您可以100%确定如果致电model.delete是因为您确实想要它。

我的解决方案适用于需要throw :abort而不是返回false的最新Rails版本。

答案 2 :(得分:0)

在Rails 6中,这是防止记录被删除的方法。 引发的异常将回滚ActiveRecord正在使用的事务,从而防止删除记录

    class MenuItem < ApplicationRecord

      after_destroy :ensure_home_page_remains

      class Error < StandardError
      end


      protected #or private whatever you need

      #Raise an error that you trap in your controller to prevent your record being deleted.
        def ensure_home_page_remains
          if menu_text == "Home"
          raise Error.new "Can't delete home page"
        end
    end

因此,sure_home_page_remains方法引发一个MenItem::Error,该事务导致回滚事务,您可以将其捕获在控制器中并采取您认为必要的任何适当操作,通常仅在重定向后向用户显示错误消息到某个地方。例如

      # DELETE /menu_items/1
      # DELETE /menu_items/1.json
      def destroy
        @menu_item.destroy
        respond_to do |format|
          format.html { redirect_to admin_menu_items_url, notice: 'Menu item was successfully destroyed.' }
          format.json { head :no_content }
        end
      end

      #Note, the rescue block is outside the destroy method
      rescue_from 'MenuItem::Error' do |exception|
        redirect_to menu_items_url, notice: exception.message
      end
private
#etc...