README.md in active_model_serializers-0.6.0 vs README.md in active_model_serializers-0.7.0
- old
+ new
@@ -1,6 +1,6 @@
-[![Build Status](https://secure.travis-ci.org/josevalim/active_model_serializers.png)](http://travis-ci.org/josevalim/active_model_serializers)
+[![Build Status](https://secure.travis-ci.org/rails-api/active_model_serializers.png)](http://travis-ci.org/rails-api/active_model_serializers)
# Purpose
The purpose of `ActiveModel::Serializers` is to provide an object to
encapsulate serialization of `ActiveModel` objects, including `ActiveRecord`
@@ -13,15 +13,15 @@
In short, **serializers replaces hash-driven development with object-oriented
development.**
# Installing Serializers
-For now, the easiest way to install `ActiveModel::Serializers` is to add this
+For now, the easiest way to install `ActiveModel::Serializers` is to add it
to your `Gemfile`:
```ruby
-gem "active_model_serializers", :git => "git://github.com/josevalim/active_model_serializers.git"
+gem "active_model_serializers", "~> 0.6.0"
```
Then, install it on the command line:
```
@@ -32,21 +32,29 @@
The easiest way to create a new serializer is to generate a new resource, which
will generate a serializer at the same time:
```
-$ rails g resource post title:string body:string
+$ rails g resource post title:string body:string
```
This will generate a serializer in `app/serializers/post_serializer.rb` for
your new model. You can also generate a serializer for an existing model with
the serializer generator:
```
$ rails g serializer post
```
+### Support for PORO's and other ORM's.
+
+Currently `ActiveModel::Serializers` adds serialization support to all models
+that descend from `ActiveRecord`. If you are using another ORM or if you are
+using objects that are `ActiveModel` compliant, but do not descend from
+`ActiveRecord`. You must add an include statement for
+`ActiveModel::SerializerSupport`.
+
# ActiveModel::Serializer
All new serializers descend from ActiveModel::Serializer
# render :json
@@ -62,11 +70,11 @@
end
end
```
In this case, Rails will look for a serializer named `PostSerializer`, and if
-it exists, use it to serialize the `Post`.
+it exists, use it to serialize the `Post`.
This also works with `respond_with`, which uses `to_json` under the hood. Also
note that any options passed to `render :json` will be passed to your
serializer and available as `@options` inside.
@@ -130,11 +138,13 @@
more concise json. To disable the root element for arrays, you have 3 options:
#### 1. Disable root globally for in `ArraySerializer`. In an initializer:
```ruby
-ActiveModel::ArraySerializer.root = false
+ActiveSupport.on_load(:active_model_serializers) do
+ ActiveModel::ArraySerializer.root = false
+end
```
#### 2. Disable root per render call in your controller:
```ruby
@@ -165,11 +175,24 @@
To specify a custom serializer for the items within an array:
```ruby
render :json => @posts, :each_serializer => FancyPostSerializer
```
+#### 4. Define default_serializer_options in your controller
+If you define `default_serializer_options` method in your controller,
+all serializers in actions of this controller and it's children will use them.
+One of options may be `root: false`
+
+```ruby
+def default_serializer_options
+ {
+ root: false
+ }
+end
+```
+
## Getting the old version
If you find that your project is already relying on the old rails to_json
change `render :json` to `render :json => @your_object.to_json`.
@@ -205,12 +228,11 @@
end
end
```
Within a serializer's methods, you can access the object being
-serialized as either `object` or the name of the serialized object
-(e.g. `admin_comment` for the `AdminCommentSerializer`).
+serialized as `object`.
You can also access the `scope` method, which provides an
authorization context to your serializer. By default, scope
is the current user of your application, but this
[can be customized](#customizing-scope).
@@ -241,10 +263,47 @@
attribute :subject, :key => :title
has_many :comments
end
```
+If you would like to add meta information to the outputted JSON, use the `:meta`
+option:
+
+```ruby
+render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}
+```
+
+The above usage of `:meta` will produce the following:
+
+```json
+{
+ "meta": { "total": 10 },
+ "posts": [
+ { "title": "Post 1", "body": "Hello!" },
+ { "title": "Post 2", "body": "Goodbye!" }
+ ]
+}
+```
+
+If you would like to change the meta key name you can use the `:meta_key` option:
+
+```ruby
+render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}, :meta_key => 'meta_object'
+```
+
+The above usage of `:meta_key` will produce the following:
+
+```json
+{
+ "meta_object": { "total": 10 },
+ "posts": [
+ { "title": "Post 1", "body": "Hello!" },
+ { "title": "Post 2", "body": "Goodbye!" }
+ ]
+}
+```
+
If you would like direct, low-level control of attribute serialization, you can
completely override the `attributes` method to return the hash you need:
```ruby
class PersonSerializer < ActiveModel::Serializer
@@ -278,11 +337,11 @@
attributes :id, :title, :body
has_many :comments
# only let the user see comments he created.
def comments
- post.comments.where(:created_by => scope)
+ object.comments.where(:created_by => scope)
end
end
```
As with attributes, you can change the JSON key that the serializer should
@@ -305,11 +364,11 @@
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body
has_many :comments
def include_comments?
- !post.comments_disabled?
+ !object.comments_disabled?
end
end
```
If you would like lower-level control of association serialization, you can
@@ -374,21 +433,21 @@
{
"post": {
"id": 1,
"title": "New post",
"body": "A body!",
- "comments": [ 1, 2, 3 ]
+ "comment_ids": [ 1, 2, 3 ]
}
}
```
Alternatively, you can choose to embed only the ids or the associated objects per association:
```ruby
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body
-
+
has_many :comments, embed: :objects
has_many :tags, embed: :ids
end
```
@@ -401,11 +460,11 @@
"title": "New post",
"body": "A body!",
"comments": [
{ "id": 1, "body": "what a dumb post" }
],
- "tags": [ 1, 2, 3 ]
+ "tag_ids": [ 1, 2, 3 ]
}
}
```
In addition to supplying an Array of IDs, you may want to side-load the data
@@ -432,15 +491,15 @@
{
"post": {
"id": 1,
"title": "New post",
"body": "A body!",
- "comments": [ 1, 2 ]
+ "comment_ids": [ 1, 2 ]
},
"comments": [
- { "id": 1, "body": "what a dumb post", "tags": [ 1, 2 ] },
- { "id": 2, "body": "i liked it", "tags": [ 1, 3 ] },
+ { "id": 1, "body": "what a dumb post", "tag_ids": [ 1, 2 ] },
+ { "id": 2, "body": "i liked it", "tag_ids": [ 1, 3 ] },
],
"tags": [
{ "id": 1, "name": "short" },
{ "id": 2, "name": "whiny" },
{ "id": 3, "name": "happy" }
@@ -474,10 +533,38 @@
{ "id": 1, "body": "what a dumb post" }
]
}
```
+You can also specify a different attribute to use rather than the ID of the
+objects:
+
+```ruby
+class PostSerializer < ActiveModel::Serializer
+ embed :ids, :include => true
+
+ attributes :id, :title, :body
+ has_many :comments, :embed_key => :external_id
+end
+```
+
+This would generate JSON that would look like this:
+
+```json
+{
+ "post": {
+ "id": 1,
+ "title": "New post",
+ "body": "A body!",
+ "comment_ids": [ "COMM001" ]
+ },
+ "comments": [
+ { "id": 1, "external_id": "COMM001", "body": "what a dumb post" }
+ ]
+}
+```
+
**NOTE**: The `embed :ids` mechanism is primary useful for clients that process
data in bulk and load it into a local store. For these clients, the ability to
easily see all of the data per type, rather than having to recursively scan the
data looking for information, is extremely useful.
@@ -494,5 +581,43 @@
```ruby
class ApplicationController < ActionController::Base
serialization_scope :current_admin
end
```
+
+Please note that, until now, `serialization_scope` doesn't accept a second
+object with options for specifying which actions should or should not take a
+given scope in consideration.
+
+To be clear, it's not possible, yet, to do something like this:
+
+```ruby
+class SomeController < ApplicationController
+ serialization_scope :current_admin, :except => [:index, :show]
+end
+```
+
+So, in order to have a fine grained control of what each action should take in
+consideration for its scope, you may use something like this:
+
+```ruby
+class CitiesController < ApplicationController
+ serialization_scope nil
+
+ def index
+ @cities = City.all
+
+ render :json => @cities, :each_serializer => CitySerializer
+ end
+
+ def show
+ @city = City.find(params[:id])
+
+ render :json => @city, :scope => current_admin?
+ end
+end
+```
+
+Assuming that the `current_admin?` method needs to make a query in the database
+for the current user, the advantage of this approach is that, by setting
+`serialization_scope` to `nil`, the `index` action no longer will need to make
+that query, only the `show` action will.