Interacting with two models - generating api ruby on rails - ruby-on-rails

I am trying to create an api rails application and i am encountering some problemes.
i got two models
A Shop with the following attributes name:string, localisation:text, size:integer
Employee with the following attributes name:string social_number:integer age:integer shop:references
A Shop can have multiple references so i thought about using belongs_to in the Employe modeland has_many in the Shop model
I am trying to create the following request POST /shops
the response should show the followings about the data of the shops
{
name: String,
localisation: text,
age: integer,
employees: List[employee]
}
And concerning the data of an employee
{
name: String,
social_number: integer,
age:integer
}
I know that I can write Shop.employees.create(name: "Yves", social_number: "12342323", age: 29) and I can see that it works in the DB.
But when I am writing the post request in the create function, how can I show the employee attribute in the body response? I can only show the attributes of the shops i.e name, localisation, age.
Thanks to the belongs_to association, I have the shop_id in the table of Employees but I don't have anything in the Shop table. How can I make a link in order to show the employees characteristics that belongs to the shop?
I'm using Rails.
Thanks all, and sorry for the long post.
Tell me if I was not clear.

Personally I would have different API calls to create a shop and an employee. So call it to create a shop, and get the shop id back. Then use this shop id in following calls to create the employees.
Alternatively, creating a shop with an number of employees, send the employee attributes as an array in the create shop request.
{
name: String,
localisation: text,
age: integer,
employees: [
{
name: String,
social_number: integer,
age:integer
},
{
name: String,
social_number: integer,
age:integer
}
]
}
The response should be similar but with ids.
{
id: integer,
name: String,
localisation: text,
age: integer,
employees: [
{
id: integer,
name: String,
social_number: integer,
age:integer
},
{
id: integer,
name: String,
social_number: integer,
age:integer
}
]
}
The employee hashes might optionally include the shop_id attribute. It doesn't hurt anything.

Related

How to return a response from rails api with ActiveRecord relations 2 levels deep?

I am creating a Rails api for teachers to rank students based on certain criteria. I have four models: classroom, student, criterion and rank.
Students/Criteria are many to many through Rank
Students/Classroom are many to many
Rank is a join table between Student/Criteria with the additional field of rank, which is an integer between 1-4.
I am able to return the list of Students belonging to a Classroom in a response (1 relation deep) by allowing Classroom.students through in my classroom serializer. How can I return each student's ranks nested within students in my Classroom response (2 relations deep) from my API? Ideal response as below:
Classroom_A:
{
id: "123",
name: "classroom A",
students: [
{ id: "456"
name: Juanita,
gender: female,
ranks: [
{ id: "789",
student_id: "456",
name: "willingness to help others",
rank: "4"
},
{ id: "101",
student_id: "456",
name: "Leadership",
rank: "3"
} ...
]
},
{ id: "232"
name: Billy,
gender: male,
ranks: [
{ id: "789",
student_id: "232",
name: "willingness to help others",
rank: "3"
},
{ id: "101",
student_id: "232",
name: "Leadership",
rank: "3"
} ...
]
}
]
}
Thanks in advance.
A similar question was posted at Rails: Serializing deeply nested associations with active_model_serializers (thanks for the link #lam Phan)
However, the most upvoted answer for that post was not super clear and there was no code example. Super dissapointing. I also looked into the JsonApi adapter and was not able to get the solution I was looking for. In the end I ended up taking the same route as the OP for the linked question: in the serializer I wrote my own function and manually sideloaded the other data that I wanted. I was hoping to do this the "Rails way" but in the end I chose to just get it done.
class ClassroomSerializer < ApplicationSerializer
attributes :id, :name, :school_name, :students
def students
customized_students = []
object.students.each do |student|
custom_student = student.attributes
custom_student['ranks'] = student.student_ranks
customized_students.push(custom_student)
end
customized_students
end
end

How do I define products with only specific property tags (Spree, Rails)

I've got a custom Spree app. I need to query Spree::Products that have the associated Spree::Property
I have a 'property' with the name "Rating" on only certain products, but I can't query those products correctly. What I have now is:
Spree::Product.joins(:properties).where(:property_name.downcase == "rating")
but that just pulls all the products that have any :properties associated with them at all.
Spree::Property -
Spree::Property(id: integer, name: string, presentation: string, created_at: datetime, updated_at: datetime)
Just tested on Spree 3.1. You can do that from Product or Property model.
Spree::Product.joins(:properties).where(spree_properties: {name: "rating"})
or
Spree::Property.where(name: "rating").first.products
*You have to modify the code to use downcase string.

update_attributes with included array one to many

How in rails, do you call update_attributes() on a active record object, and have it create appropriate rows in one-to-many associated table based on an array param.
Is this possible? Or do I need to manually loop through that param's array and insert the many rows manually via create_record() etc?
To be clear, I might have users table with 1-to-many addresses. I want to call users.update_attributes() passing in the user details to be updated, but also provide an array of addresses mapping to the addresses table.
In your User model:
model User
has_many :addresses
accepts_nested_attributes_for :addresses
end
now user can be created with this set of params
params = { user: {
name: 'Dimitri', address_attributes: [
{ country: 'Georgia', city: 'Abasha', line: '35 Kacharava Str.' },
{ country: 'USA', city: 'Los Angeles', line: '10 Infinite Loop' },
{ country: '', _destroy: '1' } # this will be ignored
]
}}
User.create(params[:user])
more details can be found from here.

mongodb many to many without join table

Originally, I specified a relationship where contact has_many services. Therefore, services has a foreign key of contact_id:
class Contact
include Mongoid::Document
field :name, type: String
end
class Service
field :name, type: String
field :contact_id, type: Integer
end
Now there is a possibility to add an additional contact to a service, so service has many contacts. However, the contacts that are added are ones that already exist independently. So I do not want to embed one entity inside another. A contact and service will always live independently. No embedding.
So should I just store the ids of the contacts inside an array of Service? In other words, my new models will look like this:
class Contact
include Mongoid::Document
field :name, type: String
end
class Service
field :name, type: String
field :contact_id, type: Integer
field :contact_ids, type: Array, default: []
end
Or is there a better solution to address the many to many problem here (without embedding one document in another)?
For the Many-To-Many, you don't have 36 options : you actually have 2 :
Array of IDs on One side like you did
Array of IDs on Both sides.
The cool thing with the "both sides" solution is that you can find query documents from both collections to get the links.
Example with books and authors :
db.books.findOne()
{
_id: 1,
title: "The Great Gatsby",
authors: [1, 5]
}
db.authors.findOne()
{
_id: 1,
firstName: "F. Scott",
lastName: "Fitzgerald",
books: [1, 3, 20]
}

MongoDB creates parent objects when I try to create child objects

This model:
class SimCustomer < Customer
index({ user_id: 1 }, { background: true })
belongs_to :user, :inverse_of => :sim_customers
end
inherits from this model:
class Customer
include Mongoid::Document
include Mongoid::Timestamps
field :mail_address, type: String
end
I create the indexes from my terminal:
bundle exec rake db:mongoid:create_indexes
But this creates indexes on the Customer instead of the SimCustomer:
I, [2014-11-13T16:21:17.210343 #11407] INFO -- : MONGOID: Created indexes on Customer:
I, [2014-11-13T16:21:17.210381 #11407] INFO -- : MONGOID: Index: {:user_id=>1}, Options: {:background=>true}
And when I try to batch insert SimCustomer objects it creates Customer objects instead:
SimCustomer.collection.insert(Array.new << {mail_address: "hello#hello.com", user_id: "54652f5b43687229b4060000"})
# => #<Customer _id: 54654b7b6220ff4f28364ee9, created_at: nil, updated_at: nil, mail_address: "hello#hello.com", _type: "Customer">
How can I fix this?
This sets up Single Collection Inheritance:
class SimCustomer < Customer
That means that both Customer and SimCustomer will be stored in the customers collection inside MongoDB and they'll be differentiated using the _type field.
Specifying an index in SimCustomer:
class SimCustomer < Customer
index({ user_id: 1 }, { background: true })
will create the index on the customers collection because that's where SimCustomers are stored.
The same collection chicanery is causing your problem with your bulk insert. If you look at SimCustomer.collection.name you'll find that it says 'customers' so of course SimCustomer.collection.insert will create new Customers. If you want to create SimCustomers by hand then specify the _type:
SimCustomer.collection.insert(
_type: 'SimCustomer',
mail_address: "hello#hello.com",
user_id: "54652f5b43687229b4060000"
)
Note that I dropped that strange looking Array.new << stuff, I don't know where you learned that from but it is unnecessary when inserting on object and odd looking if you were inserting several, if you want to insert several then just use an array literal:
SimCustomer.collection.insert([
{ ... },
{ ... },
...
])
Your next problem is going to be that string in user_id. That really should be a Moped::BSON::ObjectId or you'll end up with a string inside the database and that will make a mess of your queries. Mongoid may know what type a property should be but neither Moped nor MongoDB will. You'll want to use Moped::BSON::ObjectId('54652f5b43687229b4060000') instead.

Resources