How to handle a JSON Array POST request with Rails?

时间:2016-07-11 20:55:40

标签: ruby-on-rails json

I am trying to create multiple database entries using only one JSON request. Each entry consists only of two values, a type (of action) and a time (when the action happened). To get multiple of those into one request, I am using a JSON Array.

This is what my create action in the controller looks like:

def create

   respond_to do |format|

   @actions = []
   save_succeeded = true
   params[:action].each do |action|
      new_action = Action.new(type: action.type, time: action.time)
      save_succeeded = false unless new_action.save
      @actions << new_action
    end

    if save_succeeded
      format.json { render json: @actions, status: :created }
    else
      format.json { render json: @actions.errors, status: 501 }
    end
  end
end

When I send a post request to the controller (/actions.json) like this:

[{ "type": 0, "time": 1234567890 },{ "type": 0, "time": 1234567891 }]

I get back an empty array [] and a status code of 201 Created.

This means, the save_succeeded variable is still true, but the actions did not get added to the array. Furthermore, the actions are not in my database.

What am I doing wrong? What am I overlooking?

1 个答案:

答案 0 :(得分:0)

I would refactor the code a bit:

def create
   actions = params[:action].inject([]) do |memo, action|
     memo << Action.create!(type: action[:type], time: action[:time])
   end

   render json: @actions, status: :created

   rescue ActiveRecord::RecordInvalid => e     
     render json: e.message, status: 501
  end
end

Couple of notable changes:

  • use create! and rescue ActiveRecord::RecordInvalid - create! will raise a ActiveRecord::RecordInvalid if the save fails. Then, the rescue block will rescue the exception and you can render a nice error message.

  • you cannot use action.time, because params is a Hash, not an object.

  • if you want to build an array to render later, you can use inject.

  • if you would like to have some atomicity to this (either everything is created or nothing!), you can wrap the whole thing in a transaction block.

It's worth mentioning that I haven't tested the code above, but it should give you a direction and (maybe) it will be a drop-in replacement.

Hope that helps!