Skip to content

Fix relationship links doc #1981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Fixes:

Misc:

- [#1981](https://github.com/rails-api/active_model_serializers/pull/1981) Fix relationship link documentation. (@groyoh)
- [#1984](https://github.com/rails-api/active_model_serializers/pull/1984) Make test attributes explicit. Test models have 'associations' support. (@bf4)
- [#1993](https://github.com/rails-api/active_model_serializers/pull/1993) Swap out KeyTransform for CaseTransform gem for the possibility of native extension use (@NullVoxPopuli)

Expand Down
45 changes: 24 additions & 21 deletions docs/howto/add_relationship_links.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,42 @@ class Api::V1::UsersController < ApplicationController
serializer: Api::V1::UserSerializer,
include: []
end
end
```

Bear in mind though that ActiveModelSerializers are [framework-agnostic](outside_controller_use.md), Rails is just a common example here.

### Links as an attribute of a resource
**This is applicable to JSONAPI, JSON and Attributes adapters**
**This is applicable to JSON and Attributes adapters**

You can define an attribute in the resource, named `links`.

```ruby
class Api::V1::UserSerializer < ActiveModel::Serializer
attributes :id, :name, :links
include Rails.application.routes.url_helpers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can define an attribute in the resource, named links`.

Isn't this true for all the adapters? It's just especially confusing for JSONAPI. Also, the name links here is arbitrary once you're mixing in the url helpers and just making an attribute return an custom object (hash).

I'd also rather encourage usage of the serialization context over mixing in include Rails.application.routes.url_helpers but that's me. I sorta think using the include Rails.application.routes.url_helpers should be a way of doing it until we unify the adapters or write better docs for serialization_context.

Needs tests. That's part of the reason the doc fix is needed, right? we could put that off into a followup pr?

Copy link
Member Author

@groyoh groyoh Jan 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is working for all the adapter but not correct for JSONAPI as the spec forbid to have an attribute named links:

The value of the attributes key MUST be an object (an “attributes object”). Members of the attributes object (“attributes”) represent information about the resource object in which it’s defined.

Attributes may contain any valid JSON value.

Complex data structures involving JSON objects and arrays are allowed as attribute values. However, any object that constitutes or is contained in an attribute MUST NOT contain a relationships or links member, as those members are reserved by this specification for future use.

Also I had the url helper because within the links method there was a call to api_v1_user_path. And that call would not be correct without the url helper. I simply "fixed" the existing doc as I did not want to modify it to avoid having too many changes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose they should do it like ActiveModelSerializers::Adapter::JsonApi::Link and include ActiveModelSerializers::SerializationContext::UrlHelpers

        include ActiveModelSerializers::SerializationContext::UrlHelpers

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bf4 Well I actually followed your own advices #1981 (comment). 😁 Now who should I listen to? @bf4 from the past or @bf4 from the present? 😕

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh dear god. I guess I... good eyes @groyoh


attributes :id, :name

def links
attribute :links do
id = object.id
{
self: api_v1_user_path(object.id),
microposts: api_v1_microposts_path(user_id: object.id)
self: api_v1_user_path(id),
microposts: api_v1_microposts_path(user_id: id)
}
end
end
```

This will result in (example is in JSONAPI adapter):
Using the `JSON` adapter, this will result in:

```json
{
"data": {
"user": {
"id": "1",
"type": "users",
"attributes": {
"name": "Example User",
"links": {
"self": "/api/v1/users/1",
"microposts": "/api/v1/microposts?user_id=1"
}
"name": "John",
"links": {
"self": "/api/v1/users/1",
"microposts": "/api/v1/microposts?user_id=1"
}
}
}
Expand All @@ -58,7 +60,7 @@ This will result in (example is in JSONAPI adapter):
### Links as a property of the resource definiton
**This is only applicable to JSONAPI adapter**

You can use the `links` class method to define the links you need in the resource's primary data.
You can use the `link` class method to define the links you need in the resource's primary data.

```ruby
class Api::V1::UserSerializer < ActiveModel::Serializer
Expand All @@ -69,7 +71,8 @@ class Api::V1::UserSerializer < ActiveModel::Serializer
end
```

This will result in (example is in JSONAPI adapter):
Using the `JSONAPI` adapter, this will result in:

```json
{
"data": {
Expand Down Expand Up @@ -104,12 +107,12 @@ class Api::V1::UserSerializer < ActiveModel::Serializer

has_many :microposts, serializer: Api::V1::MicropostSerializer do
link(:related) { api_v1_microposts_path(user_id: object.id) }
end

#this is needed to avoid n+1, gem core devs are working to remove this necessity
#more on: https://github.com/rails-api/active_model_serializers/issues/1325
def microposts
object.microposts.loaded ? object.microposts : object.microposts.none
microposts = object.microposts
# The following code is needed to avoid n+1 queries.
# Core devs are working to remove this necessity.
# See: https://github.com/rails-api/active_model_serializers/issues/1325
microposts.loaded? ? microposts : microposts.none
end
end
```
Expand Down