16

我被这个问题难住了。

ActiveSupport::JSON定义to_json了各种核心对象,JSON gem 也是如此。但是,实现并不相同——ActiveSupport 版本带有参数,而 JSON gem 版本则没有。

我安装了一个需要 JSON gem 的 gem,但我的应用程序坏了。问题是我to_json在返回对象列表的控制器中使用,但我想控制返回哪些属性。

当我系统中任何地方的代码时,require 'json'我都会收到此错误消息:

TypeError: wrong argument type Hash (expected Data)

我尝试了一些我在网上阅读的东西来修复它,但没有任何效果。我最终重新编写了 gem 来使用ActiveSupport::JSON.decode而不是JSON.parse.

这可行,但不可持续……每次我想使用需要 JSON gem 的 gem 时,我都不能分叉 gem。

更新:这个问题的最佳解决方案是升级到 Rails 2.3 或更高版本,它修复了它。

4

6 回答 6

20

更新:即使使用 Rails 3.2,同样的问题仍未解决。就是强行加载 json gem 并覆盖它的讨厌的 hack。

最终我得到了下面的代码,完全绕过了 ActiveSupport 的to_json。把它放进去config/initializers/patches.rb,就可以做{}.jsonize或者[].jsonize生成JSON字符串了。保证不会与任何事物发生冲突。

# Undo the effect of 'active_support/core_ext/object/to_json'
require 'json'
[Object, Array, Hash].each do |klass|
  klass.class_eval <<-RUBY, __FILE__, __LINE__
    def jsonize(options = nil)
      ::JSON.generate self, :quirks_mode => true
    end
  RUBY
end

这 8 行代码使您的应用程序的 JSON 编码速度提高了50 倍。可能你也想做同样的事情。:)


在 Rails 2.3.8 之前,我一直有类似的问题。

问题是这ActiveSupport::JSON.backend = 'JSONGem'是一个半途而废的解决方案,您仍然需要自己覆盖一些编码器。(警告:对于使用 MultiJson 的 Rails 3.x,它必须ActiveSupport::JSON.backend = :json_gem至少是,否则它将默默无操作。)

就我而言,我需要覆盖String#to_json,因为 JSON gem 1.4.3 更好,因为它不会以不必要的形式盲目编码非 ascii-but-valid-UTF8 字符"\uXXXX",因此您可以获得更短的字节(好用于序列化)和易于阅读的结果("日本語"在我看来比 看起来更性感"\u65e5\u672c\u8a9e")。

这是我一直在使用的猴子补丁 - 将以下代码放入config/initializers/patches.rb

module ActiveSupport
  module JSON
    module Encoding
      class << self
        def escape(string)
          ::JSON.generate([string])[1..-2]
        end
      end
    end
  end
end

你可以自由地使用to_json任何东西——字符串、数组和哈希。

于 2010-07-19T22:23:26.313 回答
4

更新 此修复仅适用于 Rails < 2.3。正如 Giles 下面提到的,他们在 2.3 内部使用几乎相同的技术修复了这个问题。但要注意 json gem 早期在 Rails 兼容性方面的尝试( json/add/rails) ,如果需要,它会再次破坏一切。

您的意思是该require 'json'语句本身引发了该异常吗?或者你的意思是当你打电话时@something.to_json(:something => value)你得到错误?后者是我所期望的,如果您在需要 JSON gem 时遇到问题,那么我不确定发生了什么。

我刚刚遇到了 oauth gem 的这个问题。就我而言,没有真正的冲突,因为 oauth gem 不依赖于to_json实现。因此,问题在于 JSON 正在破坏 ActiveSupport 声明。我通过在加载 ActiveSupport 之前简单地要求 json 解决了这个问题。推杆

require 'json'

在里面Rails::Initializer做了诀窍(虽然把它放在块之后没有)。

这允许 ActiveSupport 破坏默认的 JSON 实现。

现在,如果您使用的是实际上依赖于 JSON 实现的 gem,to_json那么您将陷入困境。这绝对是元编程中最糟糕的,我会提倡 Rails 和 JSON gem 开发人员解决冲突,尽管这会很痛苦,因为其中一个必须破坏向后兼容性。

在短期内,gem 作者可能能够通过支持这两种实现来弥合差距。这或多或少是可行的,具体取决于 gem 如何使用该方法。最坏的情况是官方分叉(即gemgem-rails)。

于 2009-04-15T19:10:52.553 回答
3

经过一段时间的斗争......我发现最简单的解决方案是:

if defined?(ActiveSupport::JSON)
  [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].each do |klass|
   klass.class_eval do
    def to_json(*args)
      super(args)
    end
    def as_json(*args)
      super(args)
    end
   end
  end
end

加载activesupport后将其放在任何地方..

于 2012-09-07T20:16:09.053 回答
0

我很确定他们在 2.3 中修复了这个问题,但我不记得如何了。

于 2009-08-04T19:39:37.707 回答
0

我还没有尝试过,但看起来 Rails 2.3.3 给了你一些控制:

ActiveSupport::JSON.backend = 'JSONGem'

在这里找到

于 2010-01-20T09:41:08.250 回答
0

在我的特殊情况下,我有一个 Ruby(非 Rails)应用程序,它实际上加载了一个 Rails 应用程序(来自 config/environment.rb 加载)以及一些引用 json 的 gem。这让我非常头疼,因为我不能简单地更改 Rails 应用程序的 environment.rb 文件。我最终分叉了许多 gem,以便让 json 工作而不会引发可怕的 TypeError: wrong argument type Hash (expected Data) 消息。

我对这个解决方案很幸运,这与上面社区维基的答案完全相反...... http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont- play-nice.html 基本上主张 在 require 'json'之前调用 require 'active_support'

这是我让它发挥作用的唯一方法,相信我,我已经尝试了很多个月。

于 2010-04-03T23:25:32.637 回答