I have a rails-api app that serves as a backend and react app that serves as front-end.
Inside rails, I have a Schedule
model that has_many
workers
and Worker
model that belongs_to
schedule
. When a user create a new schedule, they can select a date
and choose the name
of the worker. My struggle is, I can't think of a way to pass down the worker's schedule_id
.
Here is what I have:
I have two fetch methods; each sends data/ makes POST request to the designated API.
function postSchedule(date, cb) {
return fetch(`api/schedules`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
date: date,
user_id: 1
})
}).then((response) => response.json())
.then(cb); //cb setStates schedules state in main react app
};
function postWorker(workerName, cb) {
return fetch('api/workers', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
worker: workerName,
schedule_id: //how do I know schedule_id?
})
}).then((response) => response.json())
.then(cb); //cb setStates workers state in main react app
}
Rails models:
//schedule.rb
class Schedule < ApplicationRecord
belongs_to :user
has_many :workers
end
//worker.rb
class Worker < ApplicationRecord
belongs_to :schedule, optional: true
end
Rails controllers:
//schedules_controller.rb
def create
@schedule = Schedule.new(schedule_params)
if @schedule.save
render json: @schedule
else
render json: @schedule, status: :unprocessable_entity
end
end
//workers_controller.rb
def create
@worker = Worker.new(worker_params) #params.permit(:name, :phone, :schedule_id)
if @worker.save
render json: @worker
else
render json: @worker, status: :unprocessable_entity
end
end
The form looks like this. User will be creating a new schedule and a new worker simultaneously.
If the user is creating a new schedule, obviously this schedule has not existed in DB yet, so I won't know this schedule's ID until after submission. When I am making a new worker, it requires schedule_id. How can I let Rails know what the schedule_id for this worker is?
What is a good strategy to assign to the newly created worker the newly created schedule?
My friend gave me a hint last night, and I got it to work. He said there is no way to get schedule_id information unless I submit it, got accepted, and returned a response of what that new schedule_id is.
So to solve my problem, I literally had to make two requests. First, I need to make a request to schedule model in rails, wait for rails to accept it, and wait for rails to return response
. Inside the response is the schedule_id. I .then
assign schedule_id
with that schedule ID that I got from rails.
It is a little messy, and I will need to clean it up. But this works for me:
Client.postSchedule(this.state.date, (schedule) => {
this.setState({schedules: this.state.schedules.concat([schedule])})
}).then(() => Client.postWorker(this.state.worker, this.state.phone, this.state.schedules[this.state.schedules.length - 1].id, (worker) => {
this.setState({workers: this.state.workers.concat([worker])})
})
)
The line this.state.schedules[this.state.schedules.length - 1].id
is a little obfuscate. What it really does is, I have an array of schedules where I store my schedule objects. I am just letting React know to get the last schedule in the array (that will be the newest schedule), and to give me the ID of the last schedule object in schedules array.
In short, (sends request to schedule) -> (wait response back from Rails that contains the schedule_id that I need) -> (use that schedule_id information to send another request)
. The solution is to check the then
's.
Here you can use rails accepts_nested_attributes_for in your Schedule model.
Add following line in your Schedule Model
accepts_nested_attributes_for :workers
Then in your SchedulesController, update schedule_params method.
def schedule_params
params.require(:schedule).permit(:user_id, :date, workers_attributes: [:id, :name, :phone])
end
And in your react App
function postSchedule(date, cb) {
return fetch(`api/schedules`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
date: date,
user_id: 1,
workers_attributes: [
{
name: worker_name,
phone: phone
}
]
})
}).then((response) => response.json())
.then(cb); //cb setStates schedules state in main react app
};
Now only one request will serve your purpose of creating Schedule as well as worker.
For reference http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.