I have a Rails object Product:
{
id: 1
name: 'soup'
}
And a Customer object:
{
id: 20
name: 'Ryans'
}
They are linked via:
class Product < ActiveRecord::Base
belongs_to :customer
When I call Product.to_json(methods: [:customer]), I get:
{
id: 1
name: 'soup',
customer: {
id: 20
name: 'Ryans'
}
}
But I need this to be in the format:
{
id: 1
name: 'soup',
customer_name: 'Ryans'
}
Is this possible? I'm using Rails v4.1.7
You can delegate nameto your Customer class
class Product < ActiveRecord::Base
belongs_to :customer
delegate :name, to: :customer, prefix: true
You can then do
Product.to_json(methods: [:customer_name])
Related
I am using the Self Joins to add reference to its own table.
class Employee < ApplicationRecord
belongs_to :manager, class_name: "Employee", optional: true
has_many :customers
end
class Customer
belongs_to :employee
end
I am fetching the employee data based. One employee will have one employee_head and employee_head will have a boss.
In the serializer i have
class EmployeeSerializer < ApplicationSerializer
# include FastJsonapi::ObjectSerializer
attributes :id, :name, :manager
def manager
ActiveModel::SerializableResource.new(object.manager)
end
end
when i query form employee, i am expecting:
{
employee:
{
id: 1,
name: "employee name",
customer_attributes: [
{ id: 8, name: customer_name }
],
manager: {
id: 2,
name: "employee head name",
customer_attributes: [
{ id: 8, name: customer_name }
],
manager: {
id: 3,
name: "boss name",
customer_attributes: [
{ id: 8, name: customer_name }
],
}
}
}
}
I am getting the expected data using:
Employee.includes(:customers).where(name: "employee name", employee_type: employee)
but the problem is when i hit the query, the customer information is fetched from the database multiple time. I am confuse where to use includes to avoid N+1 query to DB.
Thanks in advance
I have model Transactions that embeds many Events
class Transaction
embeds_many :events
end
Model Events has fields :name and :execute_at
class Event
field :name, type: String
field :execute_at, type: Date
embedded_in :transaction, inverse_of: :events
end
What I need to do is to sort Transactions by execute_at field of Events with specific name (lets say 'Name1'). Events are unique within each Transaction so there is no issue here.
Example:
{
amount: '123',
events: [
{
name: 'Name1',
execute_at: someday
},
{
name: 'Name5',
execute_at: someotherday
}
}
Transaction2
{
amount: '124',
events: [
{
name: 'Name1',
execute_at: someotherday
},
{
name: 'Name11',
execute_at: somerday
}
}
Basically sort these 2 transactions only taking data for sorting from events with name: 'Name1'
sorted_trans = Transaction.where('events.name' => 'Name1').order_by(:'events.execute_at'.asc)
or
sorted_trans = Transaction.where('events.name' => 'Name1').order_by(:'events.execute_at'.desc)
I have a rails api with a number of models that are being serialized by the fast_jsonapi gem.
This is what my models look like:
class Shift < ApplicationRecord
belongs_to :team, optional: true
...
class Team < ApplicationRecord
has_many :shifts
...
This is what the serializer looks like
class ShiftSerializer
include FastJsonapi::ObjectSerializer
...
belongs_to :team
...
end
The serialization works. However, even though I am including the compound team document:
def index
shifts = policy_scope(Shift).includes(:team)
options = {}
options[:include] = [:team, :'team.name', :'team.color']
render json: ShiftSerializer.new(shifts, options)
end
I'm still getting the object formatted like so:
...
relationships: {
team: {
data: {
id: "22",
type: "Team"
}
}
}
Whereas I'm expecting to get also the attributes of my team model.
fast_jsonapi implements json api specification so respond includes "included" key, where serialized data for relationships placed.That's default behavior
If you use the options[:include] you should create a serializer for the included model, and customize what is included in the response there.
in your case if you use
ShiftSerializer.new(shifts, include: [:team]).serializable_hash
you should create a new serializer serializers/team_serializer.rb
class TeamSerializer
include FastJsonapi::ObjectSerializer
attributes :name, :color
end
this way your response will be
{
data: [
{
id: 1,
type: "shift",
relationships: {
team: {
data: {
id: "22",
type: "Team"
}
}
}
}
],
included: [
id: 22,
type: "Team",
attributes: {
name: "example",
color: "red"
}
]
}
and you will find the custom data of your association in the response "included"
If you use like this then maybe solve your problem
class Shift < ApplicationRecord
belongs_to :team, optional:true
accepts_nested_attributes_for :team
end
In your ShiftSerializer.rb please write this code,
attribute :team do |object|
object.team.as_json
end
And you will get custom data that you want.
Reference: https://github.com/Netflix/fast_jsonapi/issues/160#issuecomment-379727174
Before using fast_jsonapi gem I was doing this:
render json: school.to_json(include: [classroom: [:students]])
My SchoolSerializer looks like:
class SchoolSerializer
include FastJsonapi::ObjectSerializer
attributes :name, :description, :classroom
end
How would I get the students included in the JSON result?
Also, the classroom association is including but it is displaying all the properties, is there a way to map the classroom property to a ClassroomSerializer ?
class School < ApplicationRecord
belongs_to :classroom
end
class Classroom < ApplicationRecord
has_many :students
end
class SchoolSerializer
include FastJsonapi::ObjectSerializer
attributes :name, :description
belongs_to :classroom
end
# /serializers/classroom_serializer.rb
class ClassroomSerializer
include FastJsonapi::ObjectSerializer
attributes :.... #attributes you want to show
end
Also you can add additional association to your School model, to access Students.
like this
has_many :students, through: :classroom
and then include it in School serializer directly.
Update: also please note that you can directly point to serializer class you need. (if you want to use class with different name from model as example).
class SchoolSerializer
include FastJsonapi::ObjectSerializer
attributes :name, :description
belongs_to :classroom, serializer: ClassroomSerializer
end
render json: SchoolSerializer.new(school, include: "classrooms.students")
The difference being the use of "include" when rendering the serializer. This tells the Serializer to add a key "included" to the returned JSON object.
class SchoolSerializer
include FastJsonapi::ObjectSerializer
belongs_to :classroom
has_many :students, through: :classroom
attributes :school_name, :description
end
StudentSerializer
include FastJsonapi::ObjectSerializer
belongs_to :classroom
belongs_to :school
attributes :student_name
end
render json: SchoolSerializer.new(school).serialized_json
will return a series of students with only the top level identifiers in the form
data: {
id: "123"
type: "school"
attributes: {
school_name: "Best school for Girls",
description: "Great school!"
...
},
relationships: {
students: [
{
id: "1234",
type: "student"
},
{
id: "5678",
type: "student"
}
]
}
}
whereas the include: "classroom.students" will return the full serialized Student Records in the form:
data: {
id: "123"
type: "school"
attributes: {
school_name: "Best school for Girls"
...
},
relationships: {
classroom: {
data: {
id: "456",
type: "classroom"
}
},
students: [
{
data: {
id: "1234",
type: "student"
}
},
{
data: {
id: "5678",
type: "student"
}
}
]
},
included: {
students: {
data {
id: "1234",
type: "student",
attributes: {
student_name: "Ralph Wiggum",
...
},
relationships: {
school: {
id: "123",
type: "school"
},
classroom: {
id: "456",
type: "classroom"
}
}
},
data: {
id: "5678",
type: "student",
attributes: {
student_name: "Lisa Simpson",
...
},
relationships: {
school: {
id: "123",
type: "school"
},
classroom: {
id: "456",
type: "classroom"
}
}
}
},
classroom: {
// Effectively
// ClassroomSerializer.new(school.classroom).serialized_json
},
}
}
I have the following models:
class User < ActiveRecord::Base
belongs_to :room
end
class Room < ActiveRecord::Base
has_many :users
validates :name, presence: true
validates :location, presence: true
end
I have a filtered list of users and I'm grouping the list by room like this:
users.group_by(&:room_id)
This gives me the following hash:
{
1=>[array of users belonging to room with id 1],
2=>[array of users belonging to room with id 2]
}
I would like to have an array of Rooms including their users like this:
[
{
id: 1,
name: room1,
location: location1,
users: [array of users belonging to room with id 1],
},
{
id: 2,
name: room2,
location: location2,
users: [array of users belonging to room with id 2]
}
]