I'm facing a case when a need to display information contained in my join table. For example:
# == Schema Information
#
# Table name: quality_inspections
#
# id, content
#
# =============================================================================
class QualityInspection
has_many :inspection_inspectors
has_many :inspector, through: :inspection_inspectors
end
# == Schema Information
#
# Table name: inspection_inspectors
#
# quality_inspection_id, inspector_id, inspection_date
#
# =============================================================================
class InspectionInspector
belongs_to :quality_inspection
belongs_to :user, foreign_key: :inspector_id
end
Then, I'd like to have the following json:
{
"quality_inspections": [{
"id": 1,
"content": "foo",
"inspectors": [{
"id": 1, // which is the user's id
"first_name": "Bar",
"last_name": "FooFoo",
"inspection_date": "random date"
}]
}]
}
For now, I'm doing the following in my serializer:
module Api::V1::QualityInspections
class InspectorSerializer < ActiveModel::Serializer
type :inspector
attributes :id, :first_name, :last_name, :inspection_date
def id
inspector.try(:public_send, __callee__)
end
def first_name
inspector.try(:public_send, __callee__)
end
def last_name
inspector.try(:public_send, __callee__)
end
private
def inspector
@inspector ||= object.inspector
end
end
end
Do you have any better solution ? Or maybe I'm not using the right methods on my Serializer ?
Anyway, I'm really stuck when it came to display information on a join table. Oddly, I'd the same issue when using cerebris/jsonapi-resources
Basically you do not need to worry about the "through" part of the "has many through" relationship: ActiveRecord handles that complexity for you, and it endows your models with the same API as a simple "has many" relationship would. Could you post your QualityInspectorSerializer?
@beauby Here it's :
module Api::V1::QualityInspections
class QualityInspectionSerializer < ActiveModel::Serializer
type :quality_inspection
attributes :id, :at, :quality_inspection_type, :final_decision
attribute :inspectors
def inspectors
object.inspection_inspectors.map do |ii|
Api::V1::QualityInspections::InspectorSerializer.new(ii)
end
end
end
end
Try the following:
module Api::V1::QualityInspections
class QualityInspectionSerializer < ActiveModel::Serializer
type :quality_inspection
attributes :id, :at, :quality_inspection_type, :final_decision
has_many :inspectors
end
end
though I suspect you should have has_many :inspectors, through: :inspection_inspectors (with inspectors plural, and not singular) in your QualityInspection class.
Yes, I've done it. But my original concern is about the InspectorSerializer, with the ugly inspector.try(:public_send, __callee__)
The InspectorSerializer should be:
module Api::V1::QualityInspections
class InspectorSerializer < ActiveModel::Serializer
type :inspector
attributes :id, :first_name, :last_name, :inspection_date
end
end
The thing is that inspection_date is on the join_table and the other field on the user table
Oh, I see. So what you really want to do, is to serialize a set of inspections, rather than a set of inspectors. I'd do the following:
module Api::V1::QualityInspections
class QualityInspectionSerializer < ActiveModel::Serializer
type :quality_inspection
attributes :id, :at, :quality_inspection_type, :final_decision
has_many :inspection_inspectors, key: 'inspectors'
end
end
module Api::V1::QualityInspections
class InspectionInspectorSerializer < ActiveModel::Serializer
type :inspector
attributes :id, :inspection_date
attribute :first_name do
object.user.first_name
end
attribute :last_name do
object.user.last_name
end
end
end
Looks nice, I'll give it a try.
However, I'd hope of a solution who use a serializer (UserSerializer for example).
It depends on the payload you want to achieve. Basically, if you want your API to serve an "inspection" as one object, you have to somewhat merge the user inside the inspection. But you could also have the Inspection have an Inspector, which would be serialized by an UserSerializer.
Closing for now, feel free to keep commenting if you have more questions.
Most helpful comment
@beauby Here it's :