Fast ActiveRecord Serializer
JSON serialization of ActiveRecord models and colections (relations or array of objects). Also can serialzie any Array or Hash with minimal syntax.
Installation
Add this line to your application's Gemfile:
gem 'fars'
And then execute:
$ bundle
Or install it yourself as:
$ gem install fars
Usage
Serialize instance (of Class inherited from ActiveRecord::Bace)
class Customer < ActiveRecord::Base
has_many :orders
end
Create serializer class named CustomerSerializer
or V1::CustomerSerializer
class CustomerSerializer < Fars::BaseModelSerializer
attributes :id, :name, :data, # attrs
:created_at, :updated_at, # methods
:orders # relations
def created_at
object.created_at.try(:strftime, "%F %H:%M")
end
def updated_at
object.updated_at.try(:strftime, "%F %H:%M")
end
# _metadata (optional)
def meta
abilities = [:update, :destroy].select { |a| scope.can?(a, object) }
{ abilities: abilities }
end
end
Then you can call #serialize method on object
# Option :scope is optional, can be used for providing metadata.
Customer.first.serialize scope: current_user
Available options are: :api_version
, :serializer
, :scope
, :fields
, :add_metadata
, :root_key
, :params
.
Description of this options provided in next section.
customer = Customer.first
# whould be serizlized with CustomerSerializer class
customer.serialize
# whould be serizlized with V1::CustomerSerializer class
customer.serialize api_version: 'V1'
# whould be serizlized with V1::ExtendedCustomerSerializer class
customer.serialize api_version: 'V1', serializer: "ExtendedCustomerSerializer"
You can specify model class and item root key in serializer:
class ExtendedCustomerSerializer < Fars::BaseModelSerializer
self.model = Customer
self.root_key = :client
end
Serialize relation
customers = Customer.where("1 = 1")
customers.serialize
Available some options
customers.serialize
root_key: :clients, # collection root key, default whoud be :customers, false if omit
api_version: "V1", # namesapce of model serializer class
fields: [:id, :name, :updated_at], # array of needed fields
scope: current_user, # user or ability, can be used in serializer meta method
add_metadata: true, # add or not item metadata, default is true if serializer respond_to? :meta
serializer: "ExtendedCustomerSerializer", # custom model serializer class
class_name: "Client", # item model class (can construct serializer class name from it), useful for array of objects
metadata: { limit: 10, offset: 50 }, # collection metadata (:root_key cannot be omitted)
params: { format: 'long' } # any parameters, can be accessed in serializes class
You can override serializers #available_attributes
method for providing dynamic attributes
depending on internal serializer's logic.
class CustomerSerializer < Fars::BaseModelSerializer
attributes :id, :name, :data, # attrs
:created_at, :updated_at, # methods
:orders # relations
def created_at
object.created_at.try(:strftime, "%F %H:%M")
end
def updated_at
object.updated_at.try(:strftime, "%F %H:%M")
end
def available_attributes
attributes = [:id, :name, :created_at, :updated_at, :orders]
attributes << :data if scope.can?(:view_data, object)
attributes
end
# _metadata (optional)
def meta
abilities = [:update, :destroy].select { |a| scope.can?(a, object) }
{ abilities: abilities }
end
end
Serialize array of instances
Array of instances can by serialized same as relation. In this case default collection's root_key will be constructed from first element class name (can't be empty array) or from povided class name (class_name option).
Serialize any Array
Provide root_key (false if omit) and serializer (proc, block or custom class)
array = %w{green blue grey}
# with proc
array.serialize root_key: :colors,
serializer: Proc.new { |c| { color: c }
# with block
array.serialize(root_key: :colors) { |c| { color: c } }
# with custom class
class ColorSerializer < Fars::BaseObjectSerializer
def as_json
{ color: object }
end
end
array.serialize(root_key: :colors, serializer: 'ColorSerializer')
This will produce:
{ colors: [
{ color: 'green' },
{ color: 'blue' },
{ color: 'grey' }
] }.to_json
Serialize Hash
Provide root_key (false if omit) and serializer (proc, block or custom class)
hash = {
'2014-01-01' => { visitors: 23, visits: 114 },
'2014-01-02' => { visitors: 27, visits: 217 }
}
# with proc
hash.serialize root_key: :stats,
serializer: Proc.new { |k, v| { day: k, visitors: v[:visitors] } })
# with block
hash.serialize root_key: :stats do |k, v|
{ day: k, visitors: v[:visitors] }
end
# with custom class
# object in this case is key-value pair
class StatSerializer < Fars::BaseObjectSerializer
def as_json
{ stat_key: object[0], stat_value: object[1] }
end
end
hash.serialize root_key: :stats, serializer: 'StatSerializer'
This will produce:
{ stats: [
{ day: '2014-01-01', visitors: 23 },
{ day: '2014-01-02', visitors: 27 }
] }.to_json
Serialize any object with serializer inherited from Fars::BaseObjectSerializer
Book = Struct.new(:isbn, :title, :author, :price, :count)
b1 = Book.new('isbn1', 'title1', 'author1', 10, nil)
b2 = Book.new('isbn2', 'title2', 'author2', 20.0, 4)
b3 = Book.new('isbn3', 'title3', 'author3', 30.5, 7)
book = b1
books = [b1, b2, b3]
class BookSerializer < Fars::BaseObjectSerializer
attributes :isbn, :title, :author, # attrs
:price, :count # methods
def price
"%.2f" % object.price
end
def count
object.count.to_i
end
end
# serializes any object with appropriate serializer
BookSerializer.new(book, fields: [:isbn, :title, :price]).to_json
# => { book: { isbn: 'isbn1', title: 'title1', price: '10.00' } }.to_json
# serialize collection
books.serialize(root_key: :books, # can be resolved automatically for non empty array
serializer: 'BookSerializer', # can be resolved automatically for non empty array
fields: [:isbn, :title, :price]) # all by default
# => { books: [
# { book: { isbn: 'isbn1', title: 'title1', price: '10.00' } },
# { book: { isbn: 'isbn2', title: 'title2', price: '20.00' } },
# { book: { isbn: 'isbn3', title: 'title3', price: '30.50' } }
# ] }.to_json
Contributing
- Fork it ( http://github.com/Lightpower/fars/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request