你如何处理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如何使用该方法。 最糟糕的情况是官方分叉(即gem
和gem-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'
在这里找到