Подтвердить что ты не робот

Как вы справляетесь с конфликтом между ActiveSupport:: JSON и драгоценным камнем JSON?

Я столкнулся с этой проблемой.

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

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

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

TypeError: wrong argument type Hash (expected Data)

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

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

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

4b9b3361

Ответ 1

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

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

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

require 'json'

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

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

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

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

Ответ 2

ОБНОВЛЕНИЕ. Даже с 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' является полуподобным решением, и вам все равно нужно перезаписать некоторые кодеры самостоятельно. ( ПРЕДУПРЕЖДЕНИЕ: для Rails 3.x, который использует MultiJson, он должен быть ActiveSupport::JSON.backend = :json_gem по крайней мере, или он будет беззвучно no-op.)

В моем случае мне пришлось перезаписать 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.

Ответ 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.

Ответ 4

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

Ответ 5

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

ActiveSupport::JSON.backend = 'JSONGem'

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

Ответ 6

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

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

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