【问题标题】:Making a model undeletable in Rails在 Rails 中使模型不可删除
【发布时间】:2015-03-18 18:51:00
【问题描述】:

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

这永远不会起作用:

User.first.destroy

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

【问题讨论】:

  • 您可以随时覆盖此模型中的destroy 方法。
  • @MarekLipka - 这是处理这个问题的正确方法吗?没有其他方法可以销毁模型记录吗?
  • 您可能还需要注意deleteapi.rubyonrails.org/classes/ActiveRecord/…
  • 总是有其他方法可以从数据库中销毁模型记录。您也可以覆盖公共delete 方法,但您仍然可以销毁您的记录,例如delete_all,或者您可以调用私有destroy_row 方法等。
  • 在数据库级别处理这个可能更容易,例如在 MySQL 中设置没有DELETE 权限的用户或使用BEFORE DELETE 触发器。

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


【解决方案1】:

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

class Model < ActiveRecord::Base
  before_destroy :nope

  private

  def nope
    raise "nope!" if (id == 1)
  end
end

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

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

  def should_destroy?
    id != 1
  end
end

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!

还有一个无错误的实现:

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

【讨论】:

  • 如果您已经覆盖了destroy,则不必覆盖destroy_all。如果你从before_destroy 返回虚假值,它也会防止模型被破坏。
  • 似乎before_destroy 抛出异常是要走的路。 User.first.destroy 只是一个例子。我不希望任何 Users 被破坏,不管他们是第一个还是最后一个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
  • 1970-01-01
相关资源
最近更新 更多