0

我正在尝试找到一种方法来覆盖 rails gem 中的变量actionpack/http/parameters.rb。我必须处理ndjson流,而 rails 中间件无法处理ndjson。它用ActiveSupport::JSON.decode

这是下面代码的来源

  DEFAULT_PARSERS = {
    Mime[:json].symbol => -> (raw_post) {
      data = ActiveSupport::JSON.decode(raw_post)
      data.is_a?(Hash) ? data : { _json: data }
    }
  }

尝试解析 ndjson 时出现此错误

ActionDispatch::Http::Parameters::ParseError in MyController#activity

我的目标是覆盖解析器以允许它解码 ndjson... 可能使用split(\n)而不是当前的ActiveSupport::JSON.decode.

到目前为止,我已经尝试在lib/文件夹中创建一个文件并使用以下代码,但它似乎没有进行覆盖。我如何在没有猴子补丁的情况下做到这一点

require 'lib/action_dispatch/http/parameters'

module MyParser
  module Overrides
    extend ActiveSupport::Concern

    DEFAULT_PARSERS = {
        Mime[:json].symbol => -> (raw_post) {
          data = raw_post.split("\n")
          data = ActiveSupport::JSON.decode(data)
          data.is_a?(Hash) ? data : { _json: data }
        }
    }

  end
end

ActionDispatch::Http::Parameters.include(MyParser::Overrides)

更新:

我尝试的第二种方法:

ActionDispatch::Http::Parameters.const_set(:DEFAULT_PARSERS, {
  Mime[:json].symbol => -> (raw_post) {
    data = raw_post.split("\n")
    data = ActiveSupport::JSON.decode(data)
    data.is_a?(Hash) ? data : { _json: data }
  },
})

不幸的是,它一直警告我该常量已经定义。

4

1 回答 1

0

我采取了另一种方法。我没有重新初始化常量,而是创建了一个文件config/initializers/custom_params.rb来覆盖使用该变量的方法parse_formatted_parameters此处)。DEFAULT_PARSERS从内部我能够更改json数据类型的 Proc 值。

这可以方便地覆盖该方法并允许ActionDispatch::Http::Parameters模块将 传递ndjson给我的控制器而不会出现任何解析错误。

module ActionDispatch
  module Http
    module Parameters
      extend ActiveSupport::Concern

      private

      def parse_formatted_parameters(parsers)
        parsers[Mime[:json].symbol] = Proc.new { |raw_post|
            data = ActiveSupport::JSON.decode(raw_post) rescue nil
            if !data
              data = raw_post
            end
            data.is_a?(Hash) ? data : { _json: data }
          }

        return yield if content_length.zero? || content_mime_type.nil?
        # rubocop:enable all

        strategy = parsers.fetch(content_mime_type.symbol) { return yield }

        begin
          strategy.call(raw_post)
        rescue # JSON or Ruby code block errors.
          my_logger = logger || ActiveSupport::Logger.new($stderr)
          my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"

          raise ParseError
        end
      end
    end
  end
end
于 2020-09-30T16:35:22.053 回答