我很难解决这个问题。
ActiveSupport::JSON
在各种核心对象上定义to_json
,JSON gem也是如此。但是,实现方式并不相同 - ActiveSupport版本接受参数,而JSON gem版本则不接受。
我安装了一个需要JSON gem的gem,我的应用程序坏了。问题是我在一个返回对象列表的控制器中使用to_json
,但我想控制返回哪些属性。
当我的系统中的任何地方的代码require 'json'
时,我收到以下错误消息:
TypeError: wrong argument type Hash (expected Data)
我尝试了一些我在网上阅读的东西来修复它,但没有任何效果。我最终重新编写了宝石以使用ActiveSupport::JSON.decode
代替JSON.parse
。
这样可行,但它不可持续......每次我想使用需要JSON宝石的宝石时,我都无法分配宝石。
更新:此问题的最佳解决方案是升级到Rails 2.3或更高版本,修复它。
答案 0 :(得分:19)
更新:即使使用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行代码使您的应用 50次更快地进行JSON编码。也许你想做同样的事情。 :)
直到Rails 2.3.8,我一直遇到类似的问题。
问题是ActiveSupport::JSON.backend = 'JSONGem'
是一个半解决方案,你仍然需要自己覆盖一些编码器。 (警告:对于使用MultiJson的Rails 3.x,它至少必须为ActiveSupport::JSON.backend = :json_gem
,否则它将默认为no-op。)
在我的情况下,我需要覆盖String#to_json
,因为JSON gem 1.4.3更好,因为它不会以{{1}的形式盲目编码非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
- String,Array和Hash。
答案 1 :(得分:4)
更新 此修复程序仅适用于Rails&lt; 2.3。正如Giles在下面提到的,他们使用大致相同的技术在内部修正了这个问题。但要注意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实现。
现在,如果您正在使用实际依赖于to_json
的JSON实现的gem,那么您就是一条小溪。这绝对是最糟糕的元编程,我会主张Rails和JSON gem开发人员来解决这个冲突,尽管这会很痛苦,因为其中一个必须打破向后兼容性。
在短期内,宝石作者可以通过支持两种实现来弥补差距。这或多或少可行,具体取决于gem如何使用该方法。最糟糕的情况是官方分叉(即。gem
和gem-rails
)。
答案 2 :(得分: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后把它放在任何地方..
答案 3 :(得分:0)
我很确定他们在2.3中解决了这个问题,但我不记得是怎么回事。
答案 4 :(得分:0)
答案 5 :(得分:0)
在我虽然独一无二的情况下,我有一个Ruby(非rails)应用程序实际上加载了一个Rails应用程序(来自config / environment.rb加载)以及一些引用json的gem。由于我不能简单地改变Rails应用程序的environment.rb文件,这让我感到非常头疼。 我最终分配了许多宝石,以便让json工作而不会引发可怕的TypeError:错误的参数类型Hash(预期数据)消息。
我对这个解决方案感到非常幸运,这与上面社区维基的答案正好相反...... http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont-play-nice.html 基本上主张打电话 要求'active_support' BEFORE 要求'json'
这是我能让它发挥作用的唯一方式,相信我,我已经尝试了好几个月。