0.0
Low commit activity in last 3 years
A long-lived project that still receives updates
Write a longer description or delete this line.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 2.0
~> 13.0
~> 3.0

Runtime

 Project Readme

Userializer

Ruby object JSON serializer.

Installation

Add this line to your application's Gemfile:

gem 'userializer'

And then execute:

$ bundle

Or install it yourself as:

$ gem install userializer

Usage

USerializer's DSL is relatively close to Active Model Serializer's, while having a few additional features including:

  • Attributes Conditional Declaration
  • Attributes Inline Definition

Attributes Conditional Declaration

USerializer allows you to dynamically decide wether an attribute should be serialized or not by passing its definition an if block as follows:

attributes :conditional_attr, if: proc { |_, opts| ... }

Eg: Let's say you want to serialize an Order object but want to include its price only if it's superior to 10, your serializer would look like the following:

class Order < ActiveRecord::Base
  def price
    10
  end
end

class OrderSerializer < USerializer::BaseSerializer
  attributes :price, if: proc do |obj, _|
    obj.price > 10
  end
end

In that case for example, the price attribute would be omitted from the final response.

Attributes Inline Definition

Using AMS, the only way to rewrite an attribute prior to serialization is to override it using a method with the same name, leading to something like this:

class MyObject < ActiveRecord::Base
  def random_attr
    0
  end
end

class MyObjectSerializer < ActiveModel::Serializer
  attributes :random_attr

  def random_attr
    object.random_attr + 1
  end
end

While this code works perfectly, it pushes the serialized attribute value definition back from its declaration, causing developers to lose focus when listing their serialized attributes because the overriding is done farther.

With USerializer, all of this is done in an inline way, so that you can override the attribute's value while declaring using a block as follows:

attributes :your_attribute do |object, _|
  ...
end

Our random_attr serialization would then looks like this with USerializer:

class MyObjectSerializer < USerializer::BaseSerializer
  attributes :random_attr do |object, _|
    object.random_attr + 1
  end
end

Way nicer, right?

Relationships

Just like AMS, USerializer supports has_one and has_many relationships

Collection Attributes Filtering

For has_many relationships, USerializer allow you to serialize only part of the collection that matches some criterias. It relies on the ActiveRecord scope feature :

class Product < ActiveRecord::Base
  has_many :variants
end

class Variant < ActiveRecord::Base
  belongs_to :product

  scope :available, -> { where(delete_at: nil) }
end

class ProductSerializer < USerializer::BaseSerializer
  has_many :variants, scope: :available
end

class VariantSerializer < USerializer::BaseSerializer
end

Serialized Output

The following outputs will be based an on our Order object in different situations:

  • Order is serialized without any relationships:
{
  "order": {
    "id": 1,
    "attr_1": "value_1",
    "attr_2": "value_2",
    "attr_3": "value_3",
  }
}
  • Order has a has_one relationship with a Client model
{
  "clients": [
    {
      "id": 4,
      "name": "userializer client",
      ...
    }
  ],
  "order": {
    "id": 1,
    "attr_1": "value_1",
    "attr_2": "value_2",
    "attr_3": "value_3",
    "client_id": 4
  }
}
  • Order has a has_many relationship with an Article model
{
  "articles": [
    {
      "id": 1,
      "name": "Article #1",
      ...
    },
    {
      "id": 1,
      "name": "Article #2",
      ...
    }
  ],
  "order": {
    "id": 1,
    "attr_1": "value_1",
    "attr_2": "value_2",
    "attr_3": "value_3",
    "article_ids": [1, 2]
  }
}

CompositeSerializer

Imagine you have a compound of different data that you want to return to the same payload. For example, you have an array of a Foo class and a Bar value to return. You can use a CompositeSerializer to serialize both.

array_foo = [Foo.new, Foo.new]
bar = Bar.new

CompositeSerializer.new(
  { key_foo: array_foo, key_bar: bar },
  each_serializer: { key_foo: FooCustomSerializer },
  serializer: { key_bar: BarSerializer },
  root: { key_foo: :foo_root, key_bar: :bar_root }
).to_json

this will render:

{
  "foo_root": [{... foo1 attributes ...}, {... foo2 attributes ...}],
  "bar_root": {... bar attributes ...}
}

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/AlexisMontagne/userializer.