Serialize only last record of a has_many association (as if it was a has_one association)
I have a user with many heights (stature measurements) recorded in a Height model but would like to serialize only last height (as if it was a has_many association).
I tried to create a (fake) custom has_one association but it does not give me what I was looking for...
app/serializers/user_serializer.rb
class UserSerializer < BaseSerializer
attributes :email
# has_many :heights
has_one :last_height, record_type: :height do |user|
user.heights.last
end
end
app/controllers/users_controller.rb
options[:include] = [:heights]
render json: UserSerializer.new(user, options).
As is, I get the error: "heights is not specified as a relationship on UserSerializer."
If I uncomment # has_many :heights, I get though:
{
"data": {
"id": "1",
"type": "user",
"attributes": {
"email": "[email protected]"
},
"relationships": {
"heights": {
"data": [
{
"id": "1",
"type": "height"
},
{
"id": "2",
"type": "height"
}
]
},
"lastHeight": {
"data": {
"id": "2",
"type": "height"
}
}
}
},
"included": [
{
"id": "1",
"type": "height",
"attributes": {
"value": "186.0"
}
},
{
"id": "2",
"type": "height",
"attributes": {
"value": "187.0"
}
}
]
}
But I don't want to include in the compound document all recorded heights...
Expected result
{
"data": {
"id": "1",
"type": "user",
"attributes": {
"email": "[email protected]"
},
"relationships": {
"lastHeight": {
"data": {
"id": "2",
"type": "height"
}
}
}
},
"included": [
{
"id": "2",
"type": "height",
"attributes": {
"value": "187.0"
}
}
]
}
@YassineDM - I have a very similar use case - did you come up with a workaround or otherwise solve this?
Nevermind. I got this to work the way that I wanted. My structure is this:
class Parent
has_many :children
end
class Child
belongs_to :parent
end
class ParentController < ApplicationController
def my_action
parent = Parent.find(params[:id])
child = parent.get_one_random_child
options = {}
options[:include] = [:child] # note -- this should be the same symbol as the has_one in your serializer
options[:params] = {random_child: child}
render json: MyParentSerializer.new(parent, options).serialized_json
end
end
class MyParentSerializer
include FastJsonapi::ObjectSerializer
set_id :id
set_type :parent
attributes: ...
has_one :child, serializer: MyChildSerializer do |object, params|
params[:random_child]
end
end
class MyChildSerializer
include FastJsonapi::ObjectSerializer
set_id :id
set_type :child
attributes: ...
end
The output matches your expected result above.
@hicklin-james, shouldn't we be able to do this without options[:params] in the controller?
Yes - you can put whatever you want in has_one block in the serializer. The key is that relation specified in the include: [] option matches the has_one symbol. I just tried this without the options[:params] and instead serialized object.children.first in the has_one block and it also worked like above.
Thx @hicklin-james, I left it as a side note but will come back to it and let you know...