你如何处理ActiveSupport :: JSON和JSON gem之间的冲突?

我很难过这个问题。

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

这有效,但它不可持续……每次我想要使用需要JSONgem的gem时,我都无法分配gem。

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

更新 此修复程序仅适用于Rails <2.3。 正如Giles在下面提到的,他们使用大致相同的技术在内部修正了这个问题。 但要注意json gem早期尝试Rails兼容性json/add/rails,如果明确要求,它将再次破坏所有内容。

你的意思是require 'json'声明本身会引发exception吗? 或者你的意思是当你调用@something.to_json(:something => value)你得到错误? 后者是我所期望的,如果你有一个需要JSON gem的问题,那么我不确定发生了什么。

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

 require 'json' 

Rails::Initializer里面做了伎俩(尽管把它放在块之后没有)。

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

现在,如果您正在使用实际依赖于to_json的JSON实现的to_json那么您就是一条小溪。 这绝对是最糟糕的元编程,我会主张Rails和JSON gem开发人员来解决这个冲突,尽管它会很痛苦,因为其中一个必须打破向后兼容性。

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

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

最终我得到了以下代码,完全绕过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更好,因为它不会盲目地编码"\uXXXX"forms的非ascii-but-valid-UTF8字符,而这是不必要的,所以你得到更短的字节(适合序列化)和易于阅读的结果( "日本語"看起来比我的眼睛更性感,而不是"\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 - String,Array和Hash。

经过一段时间的斗争……我找到了最简单的解决方案:

 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后把它放在任何地方..

我很确定他们在2.3中解决了这个问题,但我不记得怎么做了。

在我虽然独一无二的情况下,我有一个Ruby(非rails)应用程序实际上加载了一个Rails应用程序(来自config / environment.rb加载)以及一些引用json的gem。 这引起了巨大的麻烦,因为我不能简单地改变Rails应用程序的environment.rb文件。 我最终分配了许多gem,以便让json工作而不会引发可怕的TypeError:错误的参数类型Hash(预期数据)消息。

我对这个解决方案感到非常幸运,这与上面社区维基的答案正好相反…… http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont- play-nice.html基本上主张调用require’active_support’BEFORE要求’json’

这是我能让它发挥作用的唯一方法,并相信我,我在几个月内尝试了所有这些。

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

 ActiveSupport::JSON.backend = 'JSONGem' 

在这里找到