【问题标题】:Override method/variable in a gem rails覆盖宝石轨道中的方法/变量
【发布时间】:2021-01-12 01:45:46
【问题描述】:

我正在尝试找到一种方法来覆盖 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 }
  },
})

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

【问题讨论】:

  • 如果没有猴子补丁,你需要在上面写一些东西,使用 send 方法来调用很多内部方法。我真的不推荐它。
  • 难道 ndjson 没有它自己的 mime 类型,您可以使用它而不是在 Rails 内部到处乱跑吗?首先,我并没有真正理解响应 ndjson 请求的意义。
  • Max,我找不到任何 ndjson mime 类型,而且它确实存在,中间件仍然会抛出错误。除非我猴子修补哑剧

标签: ruby ruby-on-rails-5 actiondispatch ndjson


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-15
    相关资源
    最近更新 更多