Một vài công cụ hỗ trợ làm việc với JSON serialization trong Rails
Bài đăng này đã không được cập nhật trong 6 năm
Trong Rails, ta có nhiều gem có thể hỗ trợ ta để làm việc với JSON serialization, sau đây mình xin được giới thiệu 1 vài gem, công cụ phổ biến.
Ở đây, chúng ta sẽ dùng 2 models là Post
và Comment
.
Để có thể test example code, bạn có thể khởi tạo projetc và generate models với những câu lệnh sau:
rails new jsontest
cd jsontest
bundle exec rake db:create
bundle exec rails g model post title:string content:text published:boolean
bundle exec rails g model comment author:string body:text post_id:integer
bundle exec rake db:migrate
# app/models/post.rb
class Post < ActiveRecord::Base
has_many :comments
end
# app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
end
# Let's load the test data - bundle exec rails c
post = Post.create!(title: "Post", content: "content", published: true)
Comment.create!(post: post, author: "Author", body: "Comment")
Active Model Serializers
ActiveModel::Serializer
khá là phổ biến mặc cho master của nó chưa được release.Phiên bản ổn định hiện tại là 0.10.
Hãy bắt đầu bằng việc add gem vào Gemfile:
gem 'active_model_serializers', '~> 0.10.0'
Bây giờ, hãy generate models Post
và Comment
:
rails g serializer post
rails g serializer comment
Các file serializers sẽ được lưu trữ tại thư mục app/serializers
.Trước đó, chúng ta cần thêm vào config như sau trong config/application.rb
:
config.autoload_paths += ["#{config.root}/app/serializers"]
đảm bảo rằng phần serializers của bạn có những nội dung sau:
# app/serializers/post_serializer.rb
class PostSerializer < ActiveModel::Serializer
has_many :comments
attributes :id, :title, :content
end
# app/serializers/comment_serializer.rb
class CommentSerializer < ActiveModel::Serializer
attributes :id, :body, :author
end
Sử dụng:
post = Post.joins(:comments).first
PostSerializer.new(post).as_json # => {:id=>12, :title=>"Post", :content=>"content", :comments=>[{:id=>201, :body=>"Comment", :author=>"Author"}]}
JSONAPI-RB
jsonapi-rb
là một thư viện Ruby trực quan, bao gồm 4 thư viện độc lập: jsonapi-parser , jsonapi-renderer , jsonapi-serializable và jsonapi-deserializable
Add gem vào Gemfile:
gem 'jsonapi-rails'
bây giờ chúng ta cần update các serializers ở trong app/serializers/post_serializer.rb
và app/serializers/comment_serializer.rb
,
# app/serializers/post_serializer.rb
class PostSerializer < JSONAPI::Serializable::Resource
type 'posts'
has_many :comments
attributes :id, :title, :content
end
# app/serializers/comment_serializer.rb
class CommentSerializer < JSONAPI::Serializable::Resource
type 'comments'
attributes :id, :author, :body
end
Sử dụng:
post = Post.joins(:comments).first
renderer = JSONAPI::Serializable::Renderer.new
renderer.render(post, class: { Post: PostSerializer, Comment: CommentSerializer }, include: [:comments]) # => {:data=>{:id=>"113", :type=>:posts, :attributes=>{:id=>113,
:title=>"Post",
:content=>"content"},
:relationships=>{:comments=>{:data=>[{:type=>:comments,
:id=>"2702"}]}}}, :included=>[{:id=>"2702", :type=>:comments,
:attributes=>{:id=>2702, :author=>"Author", :body=>"Comment"}}]}
Fast JSON API
Thư viện là một JSON:API serializer
rất nhanh cho Ruby Object được tạo bởi Netflix
,
Add gem vào Gemfile:
gem 'fast_jsonapi'
update serializers để sử dụng Fast JSON API
:
# app/serializers/post_serializer.rb
class PostSerializer
include FastJsonapi::ObjectSerializer
attributes :title, :content
has_many :comments
end
# app/serializers/comment_serializer.rb
class CommentSerializer
include FastJsonapi::ObjectSerializer
attributes :id, :body, :author
end
Sử dụng:
post = Post.joins(:comments).first
PostSerializer.new(post, include: [:comments]).serializable_hash # =>
{:data=>{:id=>"12", :type=>:post, :attributes=>{:title=>"Post",
:content=>"content"}, :relationships=>{:comments=>{:data=>[{:id=>"201", :type=>:comment}]}}}, :included=>[{:id=>"201", :type=>:comment,
:attributes=>{:id=>201, :body=>"Comment", :author=>"Author"}}]}
RABL
RABL (Ruby API Builder Language) là một hệ thống Ruby template để generate JSON, Add gem vào Gemfile:
gem 'rabl'
Ở đây chúng ta không định nghĩa serializers trong app/serializers
, thay vào đó ta tạo JSON template, chẳng hạn như: app/views/post.rabl
và app/views/comment.rabl
:
# app/views/post.rabl
object @job
attributes :id, :title, :content
child :comments do
extends "comment"
end
# app/views/comment.rabl
object @comment
attributes :id, :author, :body
Sử dụng:
post = Post.joins(:comments).first
Rabl.render(post, 'post', :view_path => 'app/views', :format => :hash) #
=> {:id=>12, :title=>"Post", :content=>"content", :comments=>[{:id=>201, :author=>"Author", :body=>"Comment"}]}
JSON API Serializers
JSONAPI::Serializers
là 1 thư viện đơn giản cho serialization đối với Ruby objects và quan hệ của chúng:
Add gem vào Gemfile:
gem 'jsonapi-serializers'
Update code trong thư mục app/serializers
:
# app/serializers/post_serializer.rb
class PostSerializer
include JSONAPI::Serializer
attribute :id
attribute :title
attribute :content
has_many :comments
end
# app/serializers/comment_serializer.rb
class CommentSerializer
include JSONAPI::Serializer
attribute :id
attribute :author
attribute :body
end
Sử dụng:
post = Post.joins(:comments).first
JSONAPI::Serializer.serialize(post, include: ['comments']) # =>
{"data"=>{"type"=>"posts", "id"=>"12", "attributes"=>{"id"=>12,
"title"=>"Post", "content"=>"content"}, "links"=>{"self"=>"/posts/12"},
"relationships"=>{"comments"=>{"links"=>{"self"=>"/posts/12/relationships/comments", "related"=>"/posts/12/comments"},
"data"=>[{"type"=>"comments", "id"=>"201"}]}}},
"included"=>[{"type"=>"comments", "id"=>"201",
"attributes"=>{"id"=>201,
"author"=>"Author", "body"=>"Comment"},
"links"=>{"self"=>"/comments/201"}}]}
JBuilder
JBuilder là một gem cung cấp một DSL đơn giản để khai báo các cấu trúc JSON.Lần này chúng ta không phải cập nhật Gemfile vì gem này được thêm vào mặc định là Rails
Thông thường, các cấu trúc được lưu trữ trong các tệp có phần mở rộng json.jbuilder vì vậy chúng ta phải tạo 1 file như vậy. Áp dụng đoạn code sau vào app/views/post2.json.jbuilder
:
json.id post.id
json.title post.title
json.content post.content
json.comments(post.comments) do |comment|
json.id comment.id
json.author comment.author
json.body comment.body
end
Sử dụng:
post = Post.joins(:comments).first
# With template
renderer = ApplicationController.new
renderer.render_to_string('/post2', locals: {post: post}) # => "{\"id\":114,\"title\":\"Title 0\",\"content\":\"Content 0\",\"comments\":[{\"id\":2727,\"author\":\"Author 24\",\"body\":\"Comment 24\"}]}"
# Without template
def jbuild(*args, &block)
Jbuilder.new(*args, &block).attributes!
end
result = jbuild do |json|
json.id post.id
json.title post.title
json.content post.content
json.comments(post.comments) do |comment|
json.id comment.id
json.author comment.author
json.body comment.body
end
end
result # => {"id"=>12, "title"=>"Post", "content"=>"content", "comments"=>[{"id"=>201, "author"=>"Author", "body"=>"Comment"}]}
Tham khảo
https://buttercms.com/blog/json-serialization-in-rails-a-complete-guide
All rights reserved