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

发布于 2024-07-15 17:34:26 字数 594 浏览 7 评论 0原文

我被这个问题难住了。

ActiveSupport::JSON 在各种核心对象上定义 to_json,JSON gem 也是如此。 然而,实现并不相同——ActiveSupport 版本需要参数,而 JSON gem 版本则不需要。

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

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

TypeError:错误的参数类型哈希(预期数据)

我尝试了一些我读过的东西网上修复了一下,但是没有效果。 我最终重写了 gem 以使用 ActiveSupport::JSON.decode 而不是 JSON.parse。

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

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

I am stumped with this problem.

ActiveSupport::JSON defines to_json on various core objects and so does the JSON gem. However, the implementation is not the same -- the ActiveSupport version takes arguments and the JSON gem version doesn't.

I installed a gem that required the JSON gem and my app broke. The issue is that I'm using to_json in a controller that returns a list of objects, but I want to control which attributes are returned.

When code anywhere in my system does require 'json' I get this error message:

TypeError: wrong argument type Hash (expected Data)

I tried a couple of things that I read online to fix it, but nothing worked. I ended up re-writing the gem to use ActiveSupport::JSON.decode instead of JSON.parse.

This works but it's not sustainable...I can't be forking gems every time I want to use a gem that requires the JSON gem.

Update: The best solution of this problem is to upgrade to Rails 2.3 or higher, which fixed it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

最笨的告白 2024-07-22 17:34:26

更新:即使使用 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 - 字符串,数组和哈希。

UPDATE: Even with Rails 3.2, the same problem remains unfixed. The nasty hack to forcibly load the json gem and overwrite it, that is.

Eventually I ended up with the following code, to entirely bypass ActiveSupport's to_json completely. Put it in config/initializers/patches.rb, and you can do {}.jsonize or [].jsonize to generate JSON string. No conflicts with anything, guaranteed.

# 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

The 8 lines of code make your app 50 times faster for JSON encoding. Probably you want to do the same. :)


I've been having a similar problem up until Rails 2.3.8.

The problem is that ActiveSupport::JSON.backend = 'JSONGem' is a half-assed solution and you still need to overwrite some encoders yourself. (WARNING: for Rails 3.x, which uses MultiJson, it must be ActiveSupport::JSON.backend = :json_gem at least, or it will be silently no-op.)

In my case, I needed to overwrite String#to_json because JSON gem 1.4.3 is better in that it doesn't blindly encode non-ascii-but-valid-UTF8 characters in the form of "\uXXXX" where it's not necessary, so you get shorter bytes (good for serialization) and easy-to-read results ("日本語" looks much sexier to my eyes than "\u65e5\u672c\u8a9e").

Here's the monkey patch that I've been using - put the following code in 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

and you're free to use to_json on anything - String, Array and Hash.

心奴独伤 2024-07-22 17:34:26

更新 此修复仅适用于 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 实现。

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

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

Update This fix is only applicable to Rails < 2.3. As Giles mentions below, they fixed this in 2.3 internally using much the same technique. But beware the json gem's earlier attempt at Rails compatibility (json/add/rails), which, if required explicitly will break everything all over again.

Do you mean the require 'json' statement itself raises that Exception? Or do you mean when you call @something.to_json(:something => value) you get the error? The latter is what I would expect, if you have a problem requiring the JSON gem then I'm not sure what's going on.

I just ran into this problem with the oauth gem. In my case, there is not a true conflict, because the oauth gem doesn't depend on to_json implementation. Therefore the problem is that JSON is clobbering the ActiveSupport declarations. I solved this by simply requiring json before ActiveSupport is loaded. Putting

require 'json'

inside the Rails::Initializer did the trick (though putting it after the block did NOT).

That allows ActiveSupport to clobber the default JSON implementation instead.

Now if you are using a gem that actually depends on the JSON implementation of to_json then you are up a creek. This is definitely the worst of meta-programming, and I would advocate for the Rails and JSON gem developers to resolve the conflict, though it will be painful because one or the other will have to break backwards compatibility.

In the short term, gem authors may be able to bridge the gap by supporting both implementations. This is more or less feasible depending on how the gem uses the method. A worst case scenario is an official fork (ie. gem and gem-rails).

谎言 2024-07-22 17:34:26

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

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

After battling this for a while.. I found the simplest solution to be:

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

put that anywhere after activesupport is loaded..

紫轩蝶泪 2024-07-22 17:34:26

我很确定他们在 2.3 中修复了这个问题,但我不记得是怎么修复的。

I'm pretty sure they fixed this in 2.3 but I can't remember how.

南街女流氓 2024-07-22 17:34:26

在我虽然独特的情况下,我有一个 Ruby(非 Rails)应用程序,它实际上加载了一个 Rails 应用程序(从 config/environment.rb 加载)以及一些引用 json 的 gem。 这让我非常头疼,因为我无法简单地更改 Rails 应用程序的environment.rb 文件。
我最终分叉了一些 gem,以便让 json 正常工作,而不会引发可怕的 TypeError:错误的参数类型哈希(预期数据)消息。

我对这个解决方案有一些运气,这与上面社区维基的答案完全相反......
http:// blog.swivel.com/code/2009/03/active-support-and-json-gems-dont-play-nice.html
这基本上提倡打电话
需要“active_support”
之前
require 'json'

这是我让它工作的唯一方法,相信我,我在好几个月里尝试了一切。

In my albeit unique case, I had a Ruby (non-rails) app that actually loaded a Rails app (from a config/environment.rb load) as well as some gems that referenced json. This caused me huge headaches due to the fact that I could not simply alter the Rails app's environment.rb file.
I ended up forking a number of gems in order to get json to work without raising the dreaded TypeError: wrong argument type Hash (expected Data) message.

I had some luck with this solution, which is exactly the opposite as the community wiki's answer above...
http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont-play-nice.html
which basically advocates calling
require 'active_support'
BEFORE
require 'json'

This was the only way I could make it work, and believe me I tried everything over many months.

快乐很简单 2024-07-22 17:34:26

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

ActiveSupport::JSON.backend = 'JSONGem'

在这里找到

I've yet to try it, but it looks like Rails 2.3.3 gives you some control:

ActiveSupport::JSON.backend = 'JSONGem'

Found here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文