この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
現在ではxmlよりもyml よりも使われているであろう構造化文書の形式json。自分がド新人だったときに、「json? なんて不吉な名前の変数なんだ」と思ったのも遠い昔のことです。
json を始めとする構造化文書の便利さは、適切なライブラリを使えば 言語内の変数(hash, array 等)⇔一般的なテキスト、の変換が 容易に行えることにあります。
データを RDB に保存するとき、変数の構造が変化したとしても、 カラムを増やしたり join を行ったりせず、その項目での検索を ある程度あきらめるのであれば、容易かつ高速に、多様な形式の データを保存できます
class Samples < ActiveRecord::Migration
def self.up
create_table :samples do |t|
t.string “name”
t.text “description”
t.text “parms_json” #ここに、詳しいデータを json 化して保存する
end
def self.down
drop_table :samples
end
で、ここの「params_json」の値ですが、上の値に関しては、 サーバサイド(Ruby on Rails)で生成した場合と クライアントサイド(Ajax)で生成した場合と、 同じ形式で保存されることが期待されるのですが、 こちら、ちょっと困った「クセ」がそれぞれありました。 そのクセの内容と、対策を共有します。
0) まずはスタート
下記のような変数を(ruby の記法)
hash = {
:a => “b”, :c => [ [“あ”, “い”, “う”], [“え”, “お”, “か”] ]
}
を、
{ “a”:”b”, “c”:[ [“あ”,”い”,”う”], [“え”,”お”,”か”] ] }
という json にしたい。
1) Ruby on Rails の場合
何も考えずに hash.to_json した場合、
>> hash.to_json => “{\”a\”:\”b\”,\”c\”:[[\”\\u3042\”,\”\\u3044\”,\”\\u3046\”],[\”\\u3048\”,\”\\u304a\”,\”\\u304b\”]]}”
のように、 unicode_escape されて出力されます。 こちら、escape されて欲しくない場合、下記のような関数を作成し 出力を得ます。
def json_unescape(str)
str.gsub(/\\([\\\/]|u[0-9a-fA-F]{4})/) do
ustr = $1
if ustr.starts_with?(‘u’)
[ustr[1..-1].to_i(16)].pack(“U”)
elsif ustr == ‘\\’
‘\\\\’
else
ustr
end
end
end
出力は
>> json_unescape(hash.to_json) => “{\”a\”:\”b\”,\”c\”:[[\”あ\”,\”い\”,\”う\”],[\”え\”,\”お\”,\”か\”]]}”
2) jquery-json の場合
jquery および jquery-json を読み込んだ環境下にて、
alert(jQuery.toJSON({a:”b”, c:[[“あ”, “い”, “う”], [“え”, “お”, “か”]]}));
を実行したら、
{“a”:”b”,”c”:”[[\”あ\”, \”い\”, \”う\”], [\”え\”, \”お\”, \”か\”]]”}
のように、配列が内部でエスケープされた状態で出力されます。 上記のエスケープを解除したい場合、下記のような処理になります。
function no_escape_to_json(obj) {
return jQuery.toJSON(obj).replace(/\\\”/g, “\””).replace(/\”\[/g, “\[“).replace(/\]\”/g, “\]”);
}
1), 2) の処理とも、アドホックな対応のため、あまり推奨されないやり方になります。が、もしお困りの方がいればご参考いただきたいな、と。 また、もっと根本的なスマートなやり方がある場合、お教えいただけますと幸いです。