ActiveStorage:旧网址仍然要求弃用:combine_options in variation_key

ActiveStorage: Old urls still request deprecated :combine_options in variation_key

最近我从 Rails 6.0.3.4 升级到 6.1.3。 ActiveStorage 已弃用 combine_options,我已将其从我的应用程序中清除。所有新请求都按预期工作。 Internet 机器人(Facebook、Google、...)将 URL 缓存到托管在网站(比如我的网站)上的图像。根据我的 Rollbar 记录,他们一天要几次。

应加载 ActiveStorage 附件的缓存 URL 在 URL 中包含一个旧的 variation_key。当 blob 想要使用解码的 variation_key 加载时,我看到 combine_options 仍然存在。这会引发 500 Internal Server Error with ArgumentError (Active Storage's ImageProcessing transformer doesn't support :combine_options, as it always generates a single ImageMagick command.):.

有什么方法可以阻止这些错误的出现?

Rails 版本:6.1.3。 Ruby 版本:2.7.2p137

我已经使用一些中间件解决了这个问题。这将拦截所有传入的请求,扫描它们是否是 ActiveStorage url,找到已弃用的 combine_options 和 return 404 未找到的那些。这段代码也会报错当前环境是开发,这样就不会不小心再次引入废弃的代码了。

对于那些可能遇到同样问题的人,这是代码。

application.rb

require_relative '../lib/stopper'
config.middleware.use ::Stopper

lib/stopper.rb

class Stopper
  def initialize(app)
    @app = app
  end

  def call(env)

    req = Rack::Request.new(env)
    path = req.path

    if problematic_active_storage_url?(path)
      if ENV["RACK_ENV"] == 'development'
        raise "Problematic route, includes deprecated combine_options"
      end
      [404, {}, ['not found']]
    else
      @app.call(env)
    end
  end

  def problematic_active_storage_url?(path)
    if active_storage_path?(path) && !valid_variation_key?(variation_key_from_path(path))
      return true
    end
    false
  end

  def active_storage_path?(path)
    path.start_with?("/rails/active_storage/representations/")
  end

  def variation_key_from_path(path)
    if path.start_with?("/rails/active_storage/representations/redirect/")
      path.split('/')[6]
    elsif path.start_with?("/rails/active_storage/representations/")
      path.split('/')[5]
    end
  end

  def valid_variation_key?(var_key)
    if decoded_variation = ActiveStorage::Variation.decode(var_key)
      if transformations = decoded_variation.transformations
        if transformations[:combine_options].present?
          return false
        end
      end
    end
    true
  end
end

我认为塞子是一个很好的解决方案,但最终我想摆脱它。不幸的是,我们的大部分旧请求在几个月后仍在通过,而且没有人兑现 404。所以我决定根据以前的 rails 版本打补丁。这是我做的。

config/initalizers/active_storage.rb

Rails.application.config.after_initialize do
  require 'active_storage'
   
    ActiveStorage::Transformers::ImageProcessingTransformer.class_eval do
      private
        def operations
          transformations.each_with_object([]) do |(name, argument), list|
            if name.to_s == "combine_options"
              list.concat argument.keep_if { |key, value| value.present? and key.to_s != "host" }.to_a
            elsif argument.present?
              list << [ name, argument ]
            end
          end
        end
    end
end