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.