Блог 7even

про ruby, rails, sinatra, git и всё на свете

JSON.load и компания

В работе над текущим проектом мне часто приходится иметь дело с форматом json, причем не только выдавать json ответом с сервера, но еще и читать json-параметры запросов, и даже наборы параметров, сериализованные в json и уложенные в поле в таблице БД.

В ruby, как известно, для этого существует стандартная библиотека json. Упаковка данных в json и распаковка их обратно происходит с помощью 2 методов:

1
2
3
4
JSON.dump(a: 1, b: 2)
# => '{"a":1,"b":2}'
JSON.load('{"a":1,"b":2}')
# => {"a"=>1, "b"=>2}

И все бы хорошо, да вот только в один прекрасный день моя коллега на своей ubuntu-машине запустила спеки, и JSON.load почему-то повел себя как IO.load - решил, что параметром ему подсовывают имя файла - но файла под названием {"result":true} рядом не нашлось, и случился Errno::ENOENT: No such file or directory

Поначалу проблема казалась абсолютно мистической и необъяснимой, и JSON.load было решено поменять во всем проекте на ActiveSupport::JSON.decode - он работал без проблем как на убунтах коллег, так и на моем маке.

Но однажды я забыл об этой особенности, и продеплоил код на staging-сервер. Результат не заставил себя ждать - JSON.load снова захотел получить параметром путь к некоему файлу. Можно было бы, конечно, снова заменить его на вариант из ActiveSupport, но я решил, что раз уж код работает у меня на маке, то должен работать везде (уж такие вещи, как JSON, точно не должны быть платформозависимыми).

После долгих мытарств выяснилось, что ruby необходимо скомпилировать с поддержкой iconv. Причем речь идет именно о ruby - сам iconv был уже установлен на сервере, но интерпретатор об этом понятия не имел.

В случае использования RVM все это сводится к 3 командам (к сожалению, включающим в себя переустановку текущей версии ruby):

1
2
3
$ rvm package install iconv
$ rvm remove 1.9.2
$ rvm install 1.9.2 --with-iconv-dir=$rvm_path/usr

Первая команда устанавливает iconv, причем не куда-нибудь, а в ~/.rvm/usr; вторая сносит ruby 1.9.2 - ну а третья ставит его обратно, компилируя с поддержкой iconv. Чуть более подробно этот процесс описан здесь.

После этого JSON.load / JSON.dump замечательным образом заработали.

Комментарии