Ruby gem 'jbuilder' 快速產生json物件

Adler @ 2014-08-29


JSON_builder

在Rails當中,有時必須使用產生json格式回應,例如小弟目前正參與的專案就是搭配前端的Angular JS,專吃json,因此Rails從ActiveRecord抓資料出來回應給前端時,就必須包裝成json格式。

由於有些json格式規模很大,需要自訂的欄位也非常多,Rails內建的json功能不敷使用,因此使用jbuilder這個Ruby gem,可以快速產生一個自訂的json,撰寫的格式也簡單明瞭。

RailsCast上也有非常詳盡的影片說明。

Rails內建產生json物件的方法

在Rails當中已有自行產生json的方法,第一種是最簡單的,直接在頁面上產生json物件:

def index
  @posts = Post.all
  render json: @posts
end

#只送出每一個post的title
def only_title
  @posts = Post.all
  render json: @posts, :only => :title
end

另外一種是用respond_to的方法來產生:

def index
  @posts = Post.all
  respond_to do |format|
        format.html
        format.json { render :json => @posts }
  end
end

#只產生title和excerpt
def only_title_and_excerpt
  @posts = Post.all
  respond_to do |format|
        format.html
        format.json { render :json => @posts.as_json(:only => [:title, :excerpt]) }
  end
end

從以上的第一種方式,還看不出有什麼問題;但從第二個方法,就可以看出因為有各種條件限制的關係,code後方會變得太複雜。假如今天還要包含其他model的物件,例如author,那就要加上:include => :author,如果又要在底下限制只顯示id,又要使用:only => [:id]方法,搞到最後整個code會變得很長,很難管理。

使用jbuilder的好處

1. 不需要在controller內打respond_to,精簡 2. 在額外的頁面建立json格式,不用跟其他的code混在一起 3. 快速自訂格式 4. 可以在頁面中混搭method和變數,讓產生出來的data很有彈性

安裝

首先在Gemfile中輸入要安裝的jbuilder gem:

gem 'jbuilder'

接下來在Terminal中進行bundle install

$ bundle

用法

以上方post controller為例,需要自行在view當中產生一個index.json.jbuilder。

接著,只要在網址列中打上 https://your_domain.com/posts.json ,也就是在原本的網址最後方加上.json,就可以讀取該jbuilder產生的檔案。

可以把controller中的action乾淨俐落。

def index
  @posts = Post.all
end

接著我們就可以編輯index.json.jbuilder檔案,簡易用法如下:

# 讀取@posts中的欄位,自動填入
# post = Post.all
json.extract! @posts, :title, :content

# 輸出至畫面時,產生以下json
{ "title": "this is a title", "content": "this is content" }

當然,可以有更多可以自訂的方式。

# 自訂欄位名稱,並且用do包成物件。以下custom開頭的內容都可以自訂,會自動輸出成文字
# @post = Post.all
json.custom_post @posts do |post|
  json.custom_title post.title
  json.custom_content post.content
end

# 輸出至畫面時,產生以下json
{ "custom_post": {"custom_title": "this is a title", "custom_content": "this is content"} }

另外,也可以利用json.array!的用法,將所有posts依序以array方式呈現,前面加一個整個物件的標題。

# @post = Post.all
json.All_posts do
  json.array!(@posts) do |post|
    json.extract! post, :id, :title, :content
  end
end

# 輸出至畫面時,產生以下json
{ All_posts: [{ "id": "1" ,"title": "this is a title", "content": "this is content" }, { "id": "1" ,"title": "this is a title", "content": "this is content" }]}

最猛的是可以設定巢狀結構,並且在裡面進行運算。

# @posts = Post.all
# @extra_info = Information.all
# @comments = Comment.all
json.All_posts @posts do |p|
  json.extract! p, :id, :title, :content, :time
  json.like p.extra_info.like_count
  json.comments @comments do |b|
      json.extract! b, :content, :author
  end
end 

當然也可以更複雜下去,這又是jbuilder最猛的地方,但前提是自己要能處理得了...其他操作說明可以參考官方文件。

補充

假如抓資料時,不想在網址最後加上.json,可以利用controller中的render :template,讓html回應同樣也以json方式輸出。

@post = Post.all
respond_to do |format|
      format.html {render template: "posts/index.json.jbuilder"}
end

其他參考資料:

Github: jbuilder

RailsCast