Rails: How to prevent the deletion of records?

痴心易碎 提交于 2021-02-09 10:12:24

问题


I have a model Country and therefore a table countries. The countries table act as a collection of iso country and currency codes and should never reduce there content (after I have filled it with seed data). Because Country is a subclass of ActiveRecord::Base it inherits class methods like destroy, delete_all and so forth which deletes records. I'm looking for a solution to prevent the deletion of records at the model level.

Ofc. I know that I can make use of the object oriented approach to solve this problem by overriding this methods (and raise for instance an error when they called), but this assumes that I have to know all the inherited methods of the base class. I would be glad if someone could offer a more elegant solution.


回答1:


There's a before_destroy callback, maybe you could take advantage of that.

before_destroy :stop_destroy

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



回答2:


Taking inspiration from Mark Swardstrom answer, I propose the following that is working also on Rails > 5.0:

Within your model:

before_destroy :stop_destroy

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

The following will make all calls to model.destroy return false and your model will not be deleted.

You can argue that still, calls to model.delete will work, and delete your record, but since these are lower level calls this makes perfectly sense to me.

You could also delete the records directly from the database if you want, but the above solution prevents deletion from the application level, which is the right place to check that.

Rubocop checks your calls to delete or delete_all and raises a warning, so you can be 100% sure that if you call model.delete is because you really want it.

My solution works on latest Rails versions where you need to throw :abort instead of returning false.




回答3:


In Rails 6 this is how I prevent records from being deleted. The exception raised will roll back the transaction that is being used by ActiveRecord therefore preventing the record being deleted

    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

So the ensure_home_page_remains method raises an MenItem::Error that causes the transaction to be rolled back which you can trap in your controller and take whatever appropriate action you feel is necessary, normally just show the error message to the user after redirecting to somewhere. e.g.

      # 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...


来源:https://stackoverflow.com/questions/39280408/rails-how-to-prevent-the-deletion-of-records

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!