views:

1761

answers:

3

Hi All,

I am trying to create an ActiveRecord object via a JSON request. However the controller fails to set the variables passed in the parameters in the newly created object. As an example, a person object has two fields: firstname and lastname.

The JSON generated by the JSON.stringify function of the JSON.org library produces:

{"firstname" : "Joe" , "lastname" : "Bloggs"}

However the controller expects the JSON to be in the form:

{ "Person" : {"firstname" : "Joe" , "lastname" : "Bloggs"} }

I am aware that in the normal course of events (for HTTP requests) the parameters for the request are nested under the class name of the model being created.

The create action in the controller is:

def create
    @person = Person.new(params[:person])

    respond_to do |format|
      if @person.save
        flash[:notice] = 'Person was successfully created.'
        format.html { redirect_to(@person) }
        format.xml  { render :xml => @person, :status => :created, :location => @person }
        format.json  { render :json => @person, :status => :created, :location => @person }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @person.errors, :status => :unprocessable_entity }
        format.json  { render :json => @person.errors, :status => :unprocessable_entity }
      end
    end
  end

What would be the neatest way for the controller to process the JSON requests as generated? Or alternatively how do you generate "correct" JSON from Javascript objects for passing to your controllers?

TIA, Adam

+3  A: 

If you are just passing a hash of all of the person parameters (rather than a nested-hash with "person" as the key) then you should just be able to do @person = Person.new(params).

Zach Langley
Would this still work for standard HTML requests or should I refactor the JSON requests out into a separate method?
Adam
No. You should really rewrite your JSON requests to pass the same kind of parameters that would be passed via HTML.
Zach Langley
Thanks Zach,I thought as much, but wanted to be sure about best practice.Cheers,Adam
Adam
+1  A: 

Alternately, Person.new(params.reject{|k,v| k != "firstname" || k != "lastname"}) would do in your Ruby.

...

Person.new({:firstname => params[:firstname], :lastname => params[:lastname]}) -- this actually works

Here's a more futureproof solution:

Person.new(params.reject{|k,v| not Person.column_names.include?(k) })
Orion Edwards
Which requires that you set up your "protected" attributes correctly, so someone can't pass in :isAdmin => true.
James Baker
+1  A: 

One idea for allowing flat JSON input such as {"firstname": "Joe", "lastname": "Bloggs"} and the nested kind you get with an HTML form would be:

@person = Person.new(params[:person] || params)

respond_to do |format|
  ..
end
Rich Apodaca