宝石轨道中的替代方法/变量

问题描述

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

这是下面代码source

  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 }
  },})

不幸的是,它不断警告我常量已被定义。

解决方法

我采取了另一种方法。我没有重新初始化常量,而是在config/initializers/custom_params.rb中创建了一个文件来覆盖使用parse_formatted_parameters变量的方法DEFAULT_PARSERShere)。在内部,我能够更改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