docs/general/serializers.md in active_model_serializers-0.10.0.rc4 vs docs/general/serializers.md in active_model_serializers-0.10.0.rc5
- old
+ new
@@ -44,10 +44,20 @@
```ruby
has_one :bio
has_one :blog, key: :site
has_one :maker, virtual_value: { id: 1 }
+
+has_one :blog do |serializer|
+ serializer.cached_blog
+end
+
+def cached_blog
+ cache_store.fetch("cached_blog:#{object.updated_at}") do
+ Blog.find(object.blog_id)
+ end
+end
```
#### ::has_many
e.g.
@@ -74,10 +84,22 @@
def blog
Blog.new(id: 999, name: 'Custom blog')
end
```
+### Polymorphic Relationships
+
+Polymorphic relationships are serialized by specifying the relationship, like any other association. For example:
+
+```ruby
+class PictureSerializer < ActiveModel::Serializer
+ has_one :imageable
+end
+```
+
+For more context, see the [tests](../../test/adapter/polymorphic_test.rb) for each adapter.
+
### Caching
#### ::cache
e.g.
@@ -105,27 +127,46 @@
### Other
#### ::type
-e.g.
+The `::type` method defines the JSONAPI [type](http://jsonapi.org/format/#document-resource-object-identification) that will be rendered for this serializer.
+It either takes a `String` or `Symbol` as parameter.
+Note: This method is useful only when using the `:json_api` adapter.
+
+Examples:
```ruby
class UserProfileSerializer < ActiveModel::Serializer
type 'profile'
end
+class AuthorProfileSerializer < ActiveModel::Serializer
+ type :profile
+end
```
-#### ::link
+With the `:json_api` adapter, the previous serializers would be rendered as:
-e.g.
+``` json
+{
+ "data": {
+ "id": "1",
+ "type": "profile"
+ }
+}
+```
+#### ::link
+
```ruby
-link :other, 'https://example.com/resource'
link :self do
- href "https://example.com/link_author/#{object.id}"
+ href "https://example.com/link_author/#{object.id}"
end
+link :author { link_author_url(object) }
+link :link_authors { link_authors_url }
+link :other, 'https://example.com/resource'
+link :posts { link_author_posts_url(object) }
```
#### #object
The object being serialized.
@@ -134,10 +175,101 @@
PR please :)
#### #scope
-PR please :)
+Allows you to include in the serializer access to an external method.
+
+It's intended to provide an authorization context to the serializer, so that
+you may e.g. show an admin all comments on a post, else only published comments.
+
+- `scope` is a method on the serializer instance that comes from `options[:scope]`. It may be nil.
+- `scope_name` is an option passed to the new serializer (`options[:scope_name]`). The serializer
+ defines a method with that name that calls the `scope`, e.g. `def current_user; scope; end`.
+ Note: it does not define the method if the serializer instance responds to it.
+
+That's a lot of words, so here's some examples:
+
+First, let's assume the serializer is instantiated in the controller, since that's the usual scenario.
+We'll refer to the serialization context as `controller`.
+
+| options | `Serializer#scope` | method definition |
+|-------- | ------------------|--------------------|
+| `scope: current_user, scope_name: :current_user` | `current_user` | `Serializer#current_user` calls `controller.current_user`
+| `scope: view_context, scope_name: :view_context` | `view_context` | `Serializer#view_context` calls `controller.view_context`
+
+We can take advantage of the scope to customize the objects returned based
+on the current user (scope).
+
+For example, we can limit the posts the current user sees to those they created:
+
+```ruby
+class PostSerializer < ActiveModel::Serializer
+ attributes :id, :title, :body
+
+ # scope comments to those created_by the current user
+ has_many :comments do
+ object.comments.where(created_by: current_user)
+ end
+end
+```
+
+Whether you write the method as above or as `object.comments.where(created_by: scope)`
+is a matter of preference (assuming `scope_name` has been set).
+
+##### Controller Authorization Context
+
+In the controller, the scope/scope_name options are equal to
+the [`serialization_scope`method](https://github.com/rails-api/active_model_serializers/blob/d02cd30fe55a3ea85e1d351b6e039620903c1871/lib/action_controller/serialization.rb#L13-L20),
+which is `:current_user`, by default.
+
+Specfically, the `scope_name` is defaulted to `:current_user`, and may be set as
+`serialization_scope :view_context`. The `scope` is set to `send(scope_name)` when `scope_name` is
+present and the controller responds to `scope_name`.
+
+Thus, in a serializer, the controller provides `current_user` as the
+current authorization scope when you call `render :json`.
+
+**IMPORTANT**: Since the scope is set at render, you may want to customize it so that `current_user` isn't
+called on every request. This was [also a problem](https://github.com/rails-api/active_model_serializers/pull/1252#issuecomment-159810477)
+in [`0.9`](https://github.com/rails-api/active_model_serializers/tree/0-9-stable#customizing-scope).
+
+We can change the scope from `current_user` to `view_context`.
+
+```diff
+class SomeController < ActionController::Base
++ serialization_scope :view_context
+
+ def current_user
+ User.new(id: 2, name: 'Bob', admin: true)
+ end
+
+ def edit
+ user = User.new(id: 1, name: 'Pete')
+ render json: user, serializer: AdminUserSerializer, adapter: :json_api
+ end
+end
+```
+
+We could then use the controller method `view_context` in our serializer, like so:
+
+```diff
+class AdminUserSerializer < ActiveModel::Serializer
+ attributes :id, :name, :can_edit
+
+ def can_edit?
++ view_context.current_user.admin?
+ end
+end
+```
+
+So that when we render the `#edit` action, we'll get
+
+```json
+{"data":{"id":"1","type":"users","attributes":{"name":"Pete","can_edit":true}}}
+```
+
+Where `can_edit` is `view_context.current_user.admin?` (true).
#### #read_attribute_for_serialization(key)
The serialized value for a given key. e.g. `read_attribute_for_serialization(:title) #=> 'Hello World'`