在 Rails 中使模型不可删除

at.*_*at. 1 ruby model ruby-on-rails ruby-on-rails-4 ruby-on-rails-4.2

确保没有人可以通过控制台或尝试调用的某个控制器删除 Rails 中的模型记录的正确方法是什么model.destroydependent: :destroy或者甚至通过尝试销毁与此不可删除模型建立关系的对象。

这永远不应该起作用:

User.first.destroy
Run Code Online (Sandbox Code Playgroud)

我绝不希望某些模型在任何情况下丢失(当然,直接访问数据库或更改 Ruby 代码除外)。

SHS*_*SHS 5

IMO 你应该分配一个before_destroy引发错误的回调。

class Model < ActiveRecord::Base
  before_destroy :nope

  private

  def nope
    raise "nope!" if (id == 1)
  end
end
Run Code Online (Sandbox Code Playgroud)

如果引发错误是不可接受的(以防它停止其他操作),您必须定义自己的destroy

class Model < ActiveRecord::Base
  def destroy
    super if should_destroy?
  end

  def should_destroy?
    id != 1
  end
end
Run Code Online (Sandbox Code Playgroud)

也会before_destroy拦截destroy_all

但以下内容将有助于destroy_all更明确地拦截:

class Model < ActiveRecord::Base
  class ActiveRecord_Relation
    def destroy_all
      where(id: 1).exists? ? raise("nope!") : super
    end
  end
end

Model.where(id: 1).destroy_all #=> nope! (nothing gets destroyed)
Model.where(id: [1, 2]).destroy_all #=> nope! (nothing gets destroyed)
Model.where(id: 2).destroy_all #=> destruction!!! carnage! HAVOC!
Run Code Online (Sandbox Code Playgroud)

以及无错误的实现:

class Model < ActiveRecord::Base
  class ActiveRecord_Relation
    def destroy_all
      err_id = 1
      return super unless where(id: err_id).exists?

      ids = pluck(:id) - [err_id]
      where(id: ids).destroy_all
    end
  end
end
Run Code Online (Sandbox Code Playgroud)