きまぐれweb/app開発日記

個人でWEBやアプリの開発してます。使用している言語・フレームワークはGo,Flutter,Rails,Vue,ionicです。これらの開発で発見したこと、思ったことを気まぐれに書いていきます。

Railsの jsonテンプレートエンジンjbuilder

RailsAPI作るなら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":[
    {・・・・・・・}]}
]}

パッと見てもよくわかりませんが、jsonjson入れ子にしています。上位の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.jbuilder

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"をした方が楽なようです。

github.com