Как вы справляетесь с конфликтом между ActiveSupport::JSON и драгоценным камнем JSON?
-
22-08-2019 - |
Вопрос
Я в тупике с этой проблемой.
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 или выше, которое исправило ее.
Решение
Обновить Это исправление применимо только к Rails < 2.3.Как упоминает Джайлс ниже, они исправили это в версии 2.3 внутренне, используя почти ту же технику.Но остерегайтесь более ранней попытки json gem обеспечить совместимость с Rails (json/add/rails
), который, если потребуется явно, сломает все заново.
Вы имеете в виду require 'json'
само утверждение вызывает это Исключение?Или ты имеешь в виду, когда ты звонишь @something.to_json(:something => value)
вы получаете сообщение об ошибке?Последнее - это то, чего я бы ожидал, если у вас возникла проблема, требующая JSON gem, то я не уверен, что происходит.
Я только что столкнулся с этой проблемой с драгоценным камнем oauth.В моем случае истинного конфликта нет, потому что gem oauth не зависит от to_json
реализация.Следовательно, проблема заключается в том, что JSON блокирует объявления ActiveSupport .Я решил это, просто потребовав json перед загрузкой ActiveSupport.Помещая
require 'json'
внутри Rails::Initializer
сделал свое дело (хотя поместил его после блока НЕ сделал).
Это позволяет ActiveSupport вместо этого блокировать реализацию JSON по умолчанию.
Теперь, если вы используете драгоценный камень, который на самом деле зависит от реализации JSON to_json
тогда вы находитесь в затруднительном положении.Это определенно худшее из метапрограммирования, и я бы посоветовал разработчикам Rails и JSON gem разрешить конфликт, хотя это будет болезненно, потому что одному или другому придется нарушить обратную совместимость.
В краткосрочной перспективе авторы gem, возможно, смогут восполнить пробел, поддержав обе реализации.Это более или менее выполнимо в зависимости от того, как драгоценный камень использует этот метод.Наихудший сценарий - это официальный форк (т.е. gem
и gem-rails
).
Другие советы
Обновить:Даже с Rails 3.2 та же проблема остается не устраненной.Отвратительный взлом, чтобы принудительно загрузить драгоценный камень json и перезаписать его, то есть.
В конце концов я пришел к следующему коду, чтобы полностью обойти activesupport's 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, но допустимые UTF8, в виде "\uXXXX"
там, где в этом нет необходимости, так что вы получаете более короткие байты (хорошо для сериализации) и удобные для чтения результаты ("日本語"
на мой взгляд, выглядит намного сексуальнее, чем "\u65e5\u672c\u8a9e"
).
Вот патч monkey, который я использовал - вставьте следующий код в 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
на чем угодно - строке, массиве и хэше.
После того, как некоторое время боролся с этим..Я нашел самое простое решение, которое должно быть:
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 load), а также некоторые драгоценные камни, которые ссылались на json.Это вызвало у меня огромную головную боль из-за того, что я не мог просто изменить файл environment.rb приложения Rails.В итоге я разветвил несколько драгоценных камней, чтобы заставить json работать, не вызывая страшного TypeError:сообщение о хэше неправильного типа аргумента (ожидаемые данные).
Мне немного повезло с этим решением, которое прямо противоположно ответу сообщества wiki выше...http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont-play-nice.html который в основном выступает за вызов требуется 'active_support' ДО ТОГО , КАК требовать 'json'
Это был единственный способ заставить это работать, и, поверьте мне, я перепробовал все на протяжении многих месяцев.
Мне еще предстоит попробовать это, но, похоже, Rails 2.3.3 дает вам некоторый контроль:
ActiveSupport::JSON.backend = 'JSONGem'