Как вы справляетесь с конфликтом между ActiveSupport :: JSON и гемом JSON? - PullRequest
14 голосов
/ 26 марта 2009

Я озадачен этой проблемой.

ActiveSupport::JSON определяет to_json в различных основных объектах, как и гем JSON. Однако реализация не та же самая - версия ActiveSupport принимает аргументы, а версия гема JSON - нет.

Я установил гем, который требовал гем JSON, и мое приложение сломалось. Проблема в том, что я использую to_json в контроллере, который возвращает список объектов, но я хочу контролировать, какие атрибуты возвращаются.

Когда код где-либо в моей системе делает require 'json', я получаю это сообщение об ошибке:

TypeError: wrong argument type Hash (expected Data)

Я попробовал пару вещей, которые я прочитал онлайн, чтобы исправить это, но ничего не помогло. В итоге я переписал камень, чтобы использовать ActiveSupport::JSON.decode вместо JSON.parse.

Это работает, но не устойчиво ... Я не могу разветвлять драгоценные камни каждый раз, когда хочу использовать драгоценный камень, для которого требуется драгоценный камень JSON.

Обновление: Лучшее решение этой проблемы - это обновить до Rails 2.3 или выше, чтобы исправить это.

Ответы [ 6 ]

19 голосов
/ 20 июля 2010

ОБНОВЛЕНИЕ : Даже с Rails 3.2 та же проблема остается нерешенной. Гадкий хак, чтобы принудительно загрузить самоцвет json и перезаписать его, то есть.

В конце концов я получил следующий код, чтобы полностью обойти 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' - это недооцененное решение, и вам все равно нужно самостоятельно перезаписать некоторые кодировщики. ( ПРЕДУПРЕЖДЕНИЕ : для Rails 3.x, в котором используется MultiJson, оно должно быть не менее 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 для чего угодно - String, Array и Hash.

4 голосов
/ 15 апреля 2009

Обновление Это исправление применимо только к Rails <2.3. Как Джайлс упоминает ниже, они исправили это в 2.3, используя почти ту же технику. Но остерегайтесь более ранней попытки json gem совместимости с Rails </em> (json/add/rails), , которая, если потребуется, явно повредит все заново.

Вы имеете в виду, что само утверждение require 'json' поднимает это исключение? Или вы имеете в виду, когда вы звоните @something.to_json(:something => value), вы получаете ошибку? Последнее, что я ожидаю, если у вас есть проблема, требующая гем JSON, я не уверен, что происходит.

Я только что столкнулся с этой проблемой с самоцветом oauth. В моем случае нет истинного конфликта, потому что гем oauth не зависит от реализации to_json. Следовательно, проблема в том, что JSON блокирует объявления ActiveSupport. Я решил эту проблему, просто запросив json перед загрузкой ActiveSupport. Ввод

require 'json'

внутри Rails::Initializer добился цели (хотя поставить его после блока НЕ).

Это позволяет ActiveSupport блокировать реализацию JSON по умолчанию.

Теперь, если вы используете gem, который на самом деле зависит от реализации JSON to_json, тогда вы в самом деле. Это определенно худшее из метапрограммирования, и я бы посоветовал разработчикам Rails и гемов JSON разрешить конфликт, хотя это будет болезненно, потому что одному или другому придется нарушить обратную совместимость.

В краткосрочной перспективе авторы гемов смогут преодолеть разрыв, поддерживая обе реализации. Это более или менее возможно в зависимости от того, как драгоценный камень использует метод. В худшем случае это официальный форк (т.е. gem и gem-rails).

3 голосов
/ 08 сентября 2012

После некоторой борьбы с этим .. Я нашел самое простое решение:

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 ..

0 голосов
/ 04 апреля 2010

В моем, хотя и уникальном случае, у меня было приложение Ruby (не-rails), которое фактически загружало приложение Rails (из загрузки config / environment.rb), а также некоторые гемы, ссылающиеся на json. Это вызвало у меня огромную головную боль из-за того, что я не мог просто изменить файл environment.rb приложения Rails. Я закончил тем, что разветвлял несколько драгоценных камней, чтобы заставить json работать, не вызывая страшного сообщения TypeError: неправильный тип аргумента Hash (ожидаемые данные).

Мне повезло с этим решением, которое совершенно противоположно ответу вики сообщества выше ... http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont-play-nice.html который в основном выступает за вызов требует 'active_support' до требуется 'JSON'

Это был единственный способ заставить это работать, и поверьте мне, я пробовал все в течение многих месяцев.

0 голосов
/ 20 января 2010

Я еще не попробовал, но похоже, что Rails 2.3.3 дает вам некоторый контроль:

ActiveSupport::JSON.backend = 'JSONGem'

Найдено здесь

0 голосов
/ 04 августа 2009

Я почти уверен, что они исправили это в 2.3, но я не помню, как.

...