Ruby gem 'jbuilder' 快速產生json物件
在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