Serializador de modelo activo de Rails: has_many y acceso al registro principal
-
20-12-2019 - |
Pregunta
Estoy intentando crear una representación JSON de algunos modelos de Rails usando Active Model Serializer, donde algunos modelos incorporan otros.Por ejemplo, tengo Evento y Asistentes, Evento tiene_y_pertenece_a_muchos asistentes.
class EventSerializer < ActiveModel::Serializer
attributes :name
has_many :attendees, serializer: AttendeeSerializer
end
class AttendeeSerializer < ActiveModel::Serializer
attributes :name
end
Esto daría como resultado JSON como { name: 'Event One', attendees: [{ name: 'Alice' }, { name: 'Bob' }] }
.
Ahora me gustaría agregar lo que los asistentes han dicho sobre el evento.Digamos que el comentario pertenece_al evento, pertenece_al asistente.Me gustaría incluir dichos comentarios en la salida serializada del evento, para que se convierta en { name: 'Event One', attendees: [{ name: 'Alice', comments: [{ text: 'Event One was great!'}] }, { name: 'Bob', comments: [] }] }
.
podría tener
class AttendeeSerializer < ActiveModel::Serializer
attributes :name
has_many :comments
end
pero eso seleccionaría todos los comentarios de este asistente para todos los eventos, no es lo que quiero.Me gustaría escribir esto, pero ¿cómo encuentro el evento particular para el cual estoy realizando la serialización?¿Puedo acceder de alguna manera al objeto 'principal' o tal vez pasar opciones a un serializador has_many?
class AttendeeSerializer < ActiveModel::Serializer
attributes :name
has_many :comments
def comments
object.comments.where(event_id: the_event_in_this_context.id)
end
end
¿Es esto algo que se puede hacer o debería simplemente compilar el JSON de otra manera para este caso de uso en particular?
Solución
Haría las cosas manualmente para tener el control:
class EventSerializer < ActiveModel::Serializer
attributes :name, :attendees
def attendees
object.attendees.map do |attendee|
AttendeeSerializer.new(attendee, scope: scope, root: false, event: object)
end
end
end
class AttendeeSerializer < ActiveModel::Serializer
attributes :name, :comments
def comments
object.comments.where(event_id: @options[:event].id).map do |comment|
CommentSerializer.new(comment, scope: scope, root: false)
end
end
end