-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
JSONAPI resource relation urls #834
Comments
It seems a good proposal but I'm not so sure how many of AMS users are using this pattern. Ex. class ArticleSerializer
has_many :comments, url: true
end But would be cool to hear more thoughts about it. btw keep up the good work! 😄 |
So the url would be generated by something along the lines of That works for me. |
The spec also allows this url to be embedded in the link object instead of replacing the link object with a url, so the original example would become: {
"type": "articles",
"id": "1",
"links": {
"comments": {
"related": "http://example.com/articles/1/comments"
}
}
} In this format, it can optionally be combined with the currently used I think that it would be better to implement support for this format than the original suggestion. From a api point of view, I think that it would make sense to use the |
Any updates on this? In the meantime, is there a workaround we can use to get the Btw, @joaomdmoura |
@krzkrzkrz not yet, there is a pagination link PR going on but not this one yet. |
The jsonapi spec has been updated since the initial proposal. The relationships can now look like: {
"links": {
"self": "...",
"related": "..."
},
"data": [],
"meta": {}
} I think that to represent this in a serializer, it could be like has_many :comments, data: true, links: {self: true, related: true} In order to include a query param in the link (for example for pagination), you could set the value of the link object to a hash, like: has_many :comments, data: false, links: {first: {page: '1'}} Or a custom url could be used by passing in an array or proc as the value in order to generate a different url to the default one for if the url structure doesn't match the default behaviour. has_many :comments, data: false, links: {self: [:article, :relationships, :comments], related: -> object { custom_path(object) } } I am happy to work on a PR once I know the desired format to define the links for relationships. |
Hey @lsylvester, tks for point out the change on relationship proposal. has_many :comments, links: true
How do you feel about it? |
👍 |
Hey guys, I repeat the @krzkrzkrz question:
|
so @SeyZ and @krzkrzkrz you could try to workaround this by creating a new adapter that inherits from json-api's one but it is almost implement the feature itself. |
I had the same problem. I created a virtual example for getting a list of posts and then clicking on it what should trigger fetching the comments. For ORMs where a hasMany relation call results in a query there will be N+1 queries performed just for returning the posts including the comments ids, where 1+1 = 2 queries should be enough. Based on the advice of @joaomdmoura I modified the adapter to solve this using a serializer given the following code: class PostSerializer < ActiveModel::Serializer
attributes :id, :title
has_many :comments, url: ->(post){ "/api/1.0/posts/#{post.id}/comments" }
end I had to combine the class CustomJsonApiAdapter < ActiveModel::Serializer::Adapter::JsonApi
def add_resource_relationships(attrs, serializer, options = {})
options[:add_included] = options.fetch(:add_included, true)
serializer.class._associations.dup.each do |name, association_options| #do |name, association, opts|
next unless object = serializer.object
if association_options[:type] == :has_many
association_value = association_options[:association_options][:url] ? [] : serializer.send(name)
association_serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options)
else
association_value = serializer.send(name)
association_serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options)
end
if association_serializer_class
association_serializer = association_serializer_class.new(
association_value,
options.except(:serializer).merge(serializer.serializer_from_options(association_options))
)
elsif !association_value.nil? && !association_value.instance_of?(Object)
association_options[:association_options][:virtual_value] = association_value
end
opts = association_options[:association_options]
attrs[:relationships] ||= {}
if association_serializer.respond_to?(:each)
if opts[:url]
add_related(attrs, name, serializer.object, opts[:url])
else
add_relationships(attrs, name, association_serializer)
end
else
if opts[:virtual_value]
add_relationship(attrs, name, nil, opts[:virtual_value])
else
add_relationship(attrs, name, association_serializer)
end
end
if options[:add_included]
Array(association_serializer).each do |association|
add_included(name, association)
end
end
end
end
def add_related(resource, name, record, related)
related_url = related.is_a?(Proc) ? related.call(record) : related
resource[:relationships] ||= {}
resource[:relationships][name] ||= { links: {} }
resource[:relationships][name][:links][:related] = related_url
end
end
ActiveModel::Serializer.config.adapter = CustomJsonApiAdapter Note that the only change is the check on the |
Note that the above code applies to 0.10.0.rc2 and fails against the current master. |
Nice @bterkuile thank you for sharing indeed this is something that we want to have no 0.10.x |
Note that this solution of merging parts of the serializer and the adapter indicates that a proper implementation using the current adapter structure will be a challenge 😄 Good luck! |
Any updates on this? |
@djsegal I'm getting some other stuff into the pipe currently but this is on my priority list. What I have in mind is a block-based syntax such as: class UserSerializer < ActiveModel::Serializer
has_many :posts do
link :self, "//api.example.com/users/#{object.id}/relationships/posts"
end
end |
Needs the url_helpers PR mentioned in #1282 (comment) |
ref #1454 |
ref: #1269 |
Closing, as I believe this feature has been merged. Feel free to reopen if needed. |
Currently, the jsonapi adapter adds resource relationships as link objects with ids and types. The jsonapi spec also allows the the resource relationship to be defined as a URL (see http://jsonapi.org/format/#document-structure-resource-relationships). For example:
There is currently no way to do this using ActiveModel::Serializers as far as I can tell.
I propose that there should be a
:url
option for the assoications methodshas_many
andbelongs_to
that can be used to generate an resource url instead of linked objects, so that the above resource could be generated by the following serializer:I am not sure if this option is useful for the other serializers, so feedback on this would be appreciated.
If you are happy with this suggestion I can work on the implementation for this.
The text was updated successfully, but these errors were encountered: