-
Notifications
You must be signed in to change notification settings - Fork 424
Adds a :links option to the relationship macros #294
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
Adds a :links option to the relationship macros #294
Conversation
This allows specifying a `:links` option to a has_many/has_one relationship, which means you can specify `self` or `related` links as per the JSON API spec (these are often useful for not loading all associated objects in a single payload)
7b0f7fa to
ef04bc3
Compare
|
Hey folks, would love to get this one in or otherwise discuss it with y'all - is there any other way for me to get in touch? Thanks! |
|
👍 |
1 similar comment
|
👍 |
|
@nikz I can take a look into this soon. I would have liked to use a convention to define the related block rather than specify it per relationship. If it's a special case then it makes sense to define such a block. How is this feature implemented in AMS? |
|
@shishirmk Convention sounds great - I guess we could just add an option that assumes you have a How about something like: has_many :actors, related_link: :actors_urlWhich would call the The syntax in AMS looks something like: has_many :actors do
link :related do
actors_url
end
include_data false
endSo I think it would require a breaking API change to support a similar syntax (and I'm not necessarily sure it's nicer). More than happy to chat about making the API better! |
|
@nikz Thanks for getting the ball rolling here. And @shishirmk thanks for being cautious about how the feature should be presented in FJ. I'm (finally) starting the migration of my largest app from AMS to FJ and we use this feature, happy to lend a hand here. The JSON API spec allows for Here is an example from the spec document: {
"type": "articles",
"id": "1",
"attributes": {
"title": "Rails is Omakase"
},
"relationships": {
"author": {
"links": {
"self": "/articles/1/relationships/author",
"related": "/articles/1/author"
},
"data": { "type": "people", "id": "9" }
}
}
}I would think a reasonable implementation could look like this: has_many :actors, include_data: true, links: {
related: -> { |object| `http://movies.com/movies/#{object.id}/actors }
}Or possibly: has_many :actors, include_data: true, links: -> { |object, params|
{ related: `http://movies.com/movies/#{object.id}/actors` }
}I think I prefer the latter, but either way, I feel this follows the JSON API spec pretty well. A few key points:
Let me know what you all think here. |
|
I really like how it was implemented in jsonapi-rb, where you can specify how to get the data for the relationship, as many links as you want, as well as whatever metadata you want. Their default is to only serialize the relationship links unless the relationship is included, in which case the data is then also serialized. This prevents additional SQL queries to get relationship ID(s) when you are not including some relationships in a request. (There is also an option to always include the linkage data.) Along those lines, I think it would make sense to implement the serialization of the linkage data in a similar fashion, and perhaps name the option key |
|
I like the explicitness of the jsonapi-rb example syntax. I think it might be hard to do that in FJ currently because it is using the block differently. Currently it is used to determine the object that should be referenced as the data. We may be able to handle both situations... but we don't use that style of syntax anywhere else now. It's currently all just hashes and Procs.
… On Aug 22, 2018, at 6:05 PM, Mark Oleson ***@***.***> wrote:
I really like how it was implemented in jsonapi-rb, where you can specify how to get the data for the relationship, as many links as you want, as well as whatever metadata you want.
Their default is to only serialize the relationship links unless the relationship is included, in which case the data is then serialized. This prevents additional SQL queries to get relationship IDs when you are not including some relationships in a request. (There is also an option to always include the linkage data.)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
@christophersansone Thank you for jumping in with your input. I like the syntax you have brought up. in the above comment. @nikz any objections to this syntax? If this looks ok. lets go ahead with this syntax. |
|
@shishirmk Thanks for the quick response. I like the syntax you mention. If that's the case, my only questions would be surrounding how to handle the relationship's A bit off topic, but along the lines of @fusion2004's comments, I do think it would be a performance win if we offered greater control to how the |
|
We are currently migrating from AMS to FJ and need this functionality as well. Is there anything blocking the merge of this PR? As to the |
lib/fast_jsonapi/relationship.rb
Outdated
| end | ||
|
|
||
| def serialize(record, serialization_params, output_hash) | ||
| def serialize(record, serialization_params, output_hash, &block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the &block argument is used anywhere in the body?
lib/fast_jsonapi/relationship.rb
Outdated
| empty_case = relationship_type == :has_many ? [] : nil | ||
| output_hash[key] = { | ||
| data: ids_hash_from_record_and_relationship(record, serialization_params) || empty_case | ||
| data: ids_hash_from_record_and_relationship(record, serialization_params) || empty_case, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The , is redundant.
|
@shishirmk No objections, but I'm not sure that's valid Ruby? We could do: has_many :actors, links: {
related: lambda { |object| `http://movies.com/movies/#{object.id}/actors` }
}But that seems equivalent to: has_many :actors, links: {
related: -> (object, params = {}) { `http://movies.com/movies/#{object.id}/actors` }
}Which is what I have (unless I'm completely mistaken?) |
|
@christophersansone IMHO having a Once this PR is sorted (and assuming it passes muster 😄) I'd be more than happy to create a separate PR adding the |
|
@YoranBrondsema thanks for the review, I've submitted fixes for those things now. (Sorry for the slow replies on this everyone - I was on holiday!) |
6194855 to
1efdd33
Compare
If you include a default empty `data` option in your JSON API response, many frontend frameworks will ignore your `related` link that could be used to load relationship records, and will instead treat the relationship as empty. This adds a `lazy_load_data` option which will: * stop the serializer attempting to load the data and; * exclude the `data` key from the final response This allows you to lazy load a JSON API relationship.
|
@shishirmk heya! I've just updated this PR to the latest upstream master. I've also added a Is this a feature that we think would be useful for the gem? Would love to get it merged, and no worries if you'd like me to make changes. I think it's a fairly common thing to want to do (e.g if you have hundreds of posts by each author, you don't necessarily want to load them all on the author listing page) Thanks! |
|
@nikz nice work on that one! It definitely looks like a common use case. |
|
@nikz thank you for all the work you have put into this. |
|
@shishirmk no problems, happy to help - let me know if there are any bugs or anything that crops up 👍 |
This allows specifying a
:linksoption to a has_many/has_one relationship, which means you can specifyselforrelatedlinks as per the JSON API spec (these are often useful for not loading all associated objects in a single payload)A few people have chatted about this option or various parts of it in issues (#253, #252, partially in #94).
I'm not 100% if this is the syntax you folks would like, but it's impossible to copy
ActiveModel::Serializersas the block to the relationship macros is already in use for sparse recordsets. For that reason, I used a:linksoption so the syntax ends up looking like:This may not be what you folks want, but I thought I'd open a quick PR and then that way we have something to discuss! I'm absolutely fine if y'all want to do this a different way, or you'd like me to change something. Cheers! ✨ 👍