0

I have a Rails server running on the background used to capture API requests. Inside Rails, I have 2 associated models: schedule and worker. schedule has_many workers and worker belongs_to schedule

I am making a POST request from React (fetch method), this is what it looks like on React:

  return fetch(`api/schedules`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      date: date,
      message: message,
      user_id: 1,
      worker_info: {name: workerName, phone: phone}
    })

On Rails schedules_controller:

  def create
    @schedule = Schedule.new(schedule_params)
    @worker = @schedule.workers.new(worker_params)
    @worker.save
    if @schedule.save
      render json: @schedule
    else
      render json: @schedule, status: :unprocessable_entity
    end
  end

  ...

  def schedule_params
    params.require(:schedule).permit(:date, :message, :user_id)
  end

  def worker_params
    params.require(:worker_info).permit(:name, :phone)
  end

Note, the codes above works fine

I want to send to api/schedules several parameters: date, message, user_id, and some worker info (name, phone).

Schedule itself has attributes date, message, and user_id. Worker has attributes name and phone. My plan is to make only one request to Rails, stub some worker info, and let Rails create worker object inside Schedule. Again, I can do that with code above.

My question is, the complexity increases when I try to send, instead of a single object worker_info, an array of worker_infos.

worker_info: [{name: workerName, phone: phone}]

(In the future, I want to send a variable amount of workers, that's why I added the array. Right now, I just need to make it work with just one)

worker_info: [{name: 'Test Worker 1', phone: '12345'}, {name: 'Test Worker 2', phone: '54321'}, ...]

I cannot figure out how to extract worker information to make worker object if I add the array []. Here is the rails server error:

Started POST "/api/schedules" for 127.0.0.1 at 2017-05-25 17:19:32 -0700
Processing by SchedulesController#create as */*
  Parameters: {"date"=>"2017-05-27T02:00:00.000Z", "message"=>"Mireya Hiya~!!", "user_id"=>1, "worker_info"=>[{"name"=>"Mireya How
e", "phone"=>"1234567890"}], "schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1, "message"=>"Hello test!!"}}
Completed 500 Internal Server Error in 11ms (ActiveRecord: 0.0ms)



NoMethodError (undefined method `permit' for #<Array:0x007f8381fd2530>):

app/controllers/schedules_controller.rb:59:in `worker_params'
app/controllers/schedules_controller.rb:20:in `create'

I am avoiding Rails' accept_nested_attributes_formethod because the way my other code is structured, it won't work and has been causing much grief.

How can I extract the information inside worker_info: [{name: workerName, phone: phone}] and create new Worker object with that?

2
  • You should probably add your worker_params method to your question since that is clearly where the error is occurring. Commented May 26, 2017 at 0:43
  • Sorry! I just realized that too. Added it on the Rails code block^ Commented May 26, 2017 at 0:46

1 Answer 1

1

Ho, man.

First of all, good on 'ya for avoiding accept_nested_attributes_for. What a cluster you-know-what.

So, the whole point of strong parameters is to be able to whitelist stuff when doing mass assignment. This doesn't really seem like a mass assignment situation, so I would abandon ship on the whole approach.

Instead, I would go bare knuckles codez. You know, something like:

app/services/api/schedules/workers_service.rb

class Api::Schedules::WorkersService

  class < self

    def call(params={})
      ...
      # do a bunch of clever stuff
      ...
    end

  end
end

And then in SchedulesController, do something like:

def create
  @schedule = Schedule.new(schedule_params)
  if @schedule.save
    Api::Schedules::WorkersService.call(
      schedule_id: @schedule.id,
      worker_info: params[:worker_info]
    )
    render json: @schedule
  else
    render json: @schedule, status: :unprocessable_entity
  end
end

You probably want to wrap some of that junk in a transaction in case things go South.

Sign up to request clarification or add additional context in comments.

3 Comments

Yo! Thanks - I am still having trouble figuring out how to save the Object. I think I got the general idea. The service ought to convert the array of object into a plain object - right? I have not much experience with this, would you mind elaborating? I did something like def call(params={}); puts params... and it shows :worker_info=>[<ActionController::Parameters {"name"=>"Mr. Cassandre Sanford", "phone"=>"(818)-943-9150"} permitted: false>]}. How do I create a worker object from that, and what should go to into call method?
It's probably a longer conversation, we can chat if you like
Hey jvillian, sure! I am available now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.