Railsの jsonテンプレートエンジンjbuilder
RailsでAPI作るならjbuilder
スマホアプリ用にjsonでデータを吐くAPIを自作するにあたって、jbuilderを使ったら便利でしたので紹介します。環境はRails 5.0.6です。
jbuilderの基本
htmlと同じようにrouteを設定し、htmlと同じようにアクションメソッドを書いてください。gemがインストールされてなければGemfileに"gem 'jbuilder' "と追記して、bundle installしてください。viewフォルダに〇〇.json.jbuilderファイルを配置します。以下、viewのファイルの書き方です。
json.jbuilderファイルは何も書かないと"{}"と表示され、Hashが置かれていることがわかります。ファイルに記述した内容がこのハッシュ内に追加されていきます。
Hash(連想配列)を作る方法
まずは一番簡単な例
json.set! "user", "name"
json.user "name"
どちらでも{"user":"name"}というHashのキーと値を作り出します。
次にHashを入れ子にする方法
json.set! "group" do json.set! "user", "name" end
または
json.group do json.set! "user", "name" end
{"group":{"user":"name"}}という入れ子のHashができます。
Array(配列)の中にHashを作る方法
@usersというactiverecordオブジェクトに入ったidとnameを取り出すとします。
json.users @users, :id, :name
これによって下記のようなjsonが出来上がります。
{users:[ {"id":1, "name":"john"}, {"id":2, "name":"paul"} ]}
これには再利用可能でDRYな書き方も別に用意されています。
まずjson.jbuilderファイルで下記の通りテンプレートを呼び出します。
json.group do json.array! @users, partial:''userlist'', as: :users end次にテンプレートの"_userlist.json.jbuilder"を同じフォルダ内に作ります。
json.extract! users, :id, :name
これで上の記法と同じ結果が得られ、テンプレートの使い回しもできます。yay!
キャッシュの設定方法
htmlと同様にキャッシュを設定してサーバーの負荷を減らすことができます。
json.cache! ['chache1', @ursers], expires_in: 5.minutes do json.users @users, :id, :name end
こんな感じでキャシュしたい部分をjson.cache!で囲んでデータと名前を渡すだけです。wow!
arrayの中にHashを作り、その中でさらにarray・hashを入れ子にする。
例えばこういうのを作りたかったのですが、なかなか苦労しました。
{"groups":[ {"group_name": "American", " users":[ {"name": "john"}, {"name": "paul"} ]}, {"group_name": "Japanese", "users":[ {・・・・・・・}]} ]}
パッと見てもよくわかりませんが、jsonでjsonを入れ子にしています。上位のjson(groups)はactive-recodのオブジェクトではなく、入れ子になった側(users)だけがactive-recordオブジェクトです。
2時間ほど詰まったのですが、下記のようにコントローラーでhashを作って渡せばいいようです。
controller.rb
@american = User.where("group = ?", "american") @japanese = User.where("group" = ?", "japanese") @groups = { "american" => @american, "japanese => @japanese }
json.array! @groups do |key,value| json.set! "group", key json.users do json.users value, :name end end
Hashを作ってそこにvalueactive-recordのオブジェクを渡すことで、なんとか作ることができました。haha!
ただ、複雑になった場合はjbuilderを使わず、controller側でhashを作って"render :json => hash"をした方が楽なようです。