D. Rakov
D. Rakov

Reputation: 338

Ruby on Rails and JSON request processing

I have ruby on rails app and my controller should process request which creates many objects. Objects data is passed from client via json using POST method.

Example of my request (log from controller):

Processing by PersonsController#save_all as JSON

Parameters: {"_json"=>[{"date"=>"9/15/2014", "name"=>"John"},
         {"date"=>"9/15/2014", "name"=>"Mike"}], "person"=>{}}

So i need to save these two users but i have some issues:

  1. How to verify strong parameters here? Only Name and Date attributes can be passed from client
  2. How can I convert String to Date if i use Person.new(params)?
  3. Can i somehow preprocess my json? For example i want to replace name="Mike" to name="Mike User" and only then pass it in my model
  4. I want to enrich params of every person by adding some default parameters, for example, i want to add status="new_created" to person params

Upvotes: 1

Views: 916

Answers (1)

Daniel
Daniel

Reputation: 3027

First of all I'd name the root param something like "users", then it gives a structure that is all connected to the controller name and the data being sent.

Regarding strong params. The config depends of your rails app version. <= 3.x doesn't have this included so you need to add the gem. If you're on >= 4.x then this is already part of rails.

Next in your controller you need to define a method that will do the filtering of the params you need. I should look something like:

class PeopleController < ApplicationController
  def some_action
    # Here you can call a service that receives people_params and takes
    # care of the creation.
    if PeopleService.new(people_params).perform
      # some logic
    else
      # some logic
    end
  end

  private

  def base_people_params
    params.permit(people: [:name, :date])
  end
  # Usually if you don't want to manipulate the params then call the method 
  # just #people_params

  def people_params
    base_people_params.merge(people: normalized_params)
  end
  # In case you decided to manipulate the params then create small methods    
  # that would that separately. This way you would be able to understand this 
  # logic when returning to this code in a couple of months.

  def normalized_params
    return [] unless params[:people]

    params[:people].each_with_object([]) do |result, person|
      result << { 
        name: normalize_name(person[:name]), 
        date: normalize_date(person[:date]),
      } 
    end
  end

  def normalize_date(date)
    Time.parse(date)
  end

  def normalize_name(name)
    "#{name} - User"
  end
end

If you see that the code starts to get to customized take into a service. It will help to help to keep you controller thin (and healthy).

When you create one reason at the time (and not a batch like here) the code is a bit simpler, you work with hashes instead of arrays... but it's all pretty much the same.

EDIT:

If you don't need to manipulate a specific param then just don't

def normalized_params
  return [] unless params[:people]

  params[:people].each_with_object([]) do |result, person|
    result << { 
      name: person[:name], 
      date: normalize_date(person[:date]),
    } 
  end
end

Upvotes: 1

Related Questions