【问题标题】:How to ignore/supress a specific type of exception (ActiveRecord::ReadOnlyRecord) across my code base如何在我的代码库中忽略/抑制特定类型的异常(ActiveRecord::ReadOnly Record)
【发布时间】:2026-02-03 13:05:01
【问题描述】:

我正在尝试创建我的应用程序的只读版本,并对 ActiveRecord::Base 进行猴子修补,以便它在所有模型中为 readonly? 返回 true

module ActiveRecord
  class Base
    def readonly?
      true
    end
  end
end 

这导致ActiveRecord::ReadOnlyRecord 异常在我尝试写入数据库的任何地方引发。有没有办法在代码中的任何地方忽略这个异常并继续执行代码。某种覆盖异常类的方法,使其不执行任何操作,即抑制异常。

【问题讨论】:

  • 也许这方面的最佳答案可以帮助你:*.com/questions/25841377/…
  • 出于好奇:为什么要将所有模型设为只读,然后又可以修改和保存它们?
  • @wiesion 我想创建我的应用程序的只读版本(特别是管理员)。一个冗长的方法可能是使用某种授权 gem,但更短的方法可能是让所有模型只读。我希望这些写入以静默方式失败,这样代码执行就不会因为引发的异常而受到阻碍,并且应用程序可以正常工作(除了没有发生写入)。
  • @ldeld 不,这无济于事,因为这只是一个包罗万象的问题。引发异常后,不会执行该行之后的代码。我想抑制特定类型的异常,以便即使发生该异常,它之后的代码也能正常执行。

标签: ruby-on-rails ruby postgresql exception


【解决方案1】:

您可以尝试以下方法,而不是将所有模型设为只读:

class ApplicationRecord < ActiveRecord::Base
  before_commit do
    raise ActiveRecord::Rollback, 'Read-only'
  end
end

【讨论】:

  • 这不会引发异常并且我仍然会得到 5xx 响应吗?即使写入数据库失败,我也希望代码继续执行。
  • @amit_saxena 这个回调会取消交易,异常不会重新引发
  • 看起来before_commit 不是可用的回调。我收到以下错误:NoMethodError: undefined method before_commit' for ApplicationRecord(abstract):Class. But this is an interesting approach - I believe if I override before_save` 和 before_destroy 以类似的方式,它应该适用于 99% 的情况(除非在应用程序以及是否有人正在使用跳过回调的方法)。
【解决方案2】:

假设

  • 您的所有模型都继承自自定义 ApplicationRecord
  • 您使用了验证
  • 通过 URL 访问模型的所有接口都不会跳过验证
  • 您希望对只读版本使用完全相同的源代码

我建议您使用全局验证,它检查环境变量是否存在,我们称之为MY_APP_IS_READ_ONLY

application_record.rb

class ApplicationRecord < ActiveRecord::Base
  # your code ...
  validates :not_read_only_mode
  def not_read_only_mode
    errors.add(:base, "App runs in read-only mode") unless ENV['MY_APP_IS_READ_ONLY'].nil?
  end

现在所有继承的模型都应该无法通过验证,并且在失败的.save 上它们会被重定向到相同的 URL(取决于您的代码),永远无法创建或更新任何记录。此外,通过将:base 指定为错误源,您可以创建不与任何字段绑定的通用错误消息。

但是,如果您有需要更新的模型(会话?上次登录的用户?),您应该创建一个单独的类来保存此验证,并让有条件的只读模型从它继承。

【讨论】:

    【解决方案3】:

    您可以在应用程序控制器中挽救异常并忽略它。

    【讨论】:

      最近更新 更多