简体   繁体   中英

How to do POST request of two associated Rails models from React?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM