eightonrose eightonrose - 6 months ago 36
Ruby Question

Rails 4 API with Strong Parameters?

I'm building a simple API with Rails 4, but with my "create" method, it all goes horribly wrong.

Here is the relevant part of my routes file:

namespace :api, defaults: { format: 'json' } do
# /api/... Api::
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :users
end
end


Here is the api/v1/users_controller.rb:

class Api::V1::UsersController < ApplicationController

protect_from_forgery except: :create
respond_to :json

def index
respond_to do |format|
format.html {render text: "Your data was sucessfully loaded. Thanks"}
format.json { render text: User.last.to_json }
end
end

def show
respond_with User.find(params[:id])
end

def create
respond_with User.create(user_params)
end

def update
respond_with User.update(params[:id], params[:users])
end

def destroy
respond_with User.destroy(params[:id])
end

private

def user_params
params.require(:user).permit(:name, :age, :location, :genre_ids => [], :instrument_ids => [])
end
end


Whenever I try to add an API with JSON, I get "{"errors":{"name":["can't be blank"]}}"

It works to create a user with my regular controller, but I have a feeling my API controller is getting messed up because of the Strong Parameters.

Any suggestions for how to do this correctly in Rails 4?
Also, I have a few Has-Many-Through relationships through my user model. The API's user controller should be able to see that off the bat, right?

Thanks

EDIT:

I'm now getting this error:
enter image description here

EDIT:

{
"name": "Sally",
"age": "23",
"location": "Blue York",
"genre_ids": [1, 2, 3]
}


EDIT AGAIN

Even with adding the User parameter in my JSON call, it still gives me the same error of the :user param missing. Am I using strong parameters incorrectly? In my "regular" users_controller, I can create a user easily with a form that I have set up, but with this API controller, I can't seem to create one with JSON. Any other suggestions?

EDIT YET AGAIN
*Here Is The Log From Start to Error*

rails s
=> Booting WEBrick
=> Rails 4.0.1 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2013-12-19 14:03:01] INFO WEBrick 1.3.1
[2013-12-19 14:03:01] INFO ruby 1.9.3 (2013-02-22) [x86_64-darwin10.8.0]
[2013-12-19 14:03:01] INFO WEBrick::HTTPServer#start: pid=53778 port=3000


Started GET "/api/users" for 127.0.0.1 at 2013-12-19 14:03:02 -0500
ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by Api::V1::UsersController#index as JSON
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
Rendered text template (0.0ms)
Completed 200 OK in 142ms (Views: 27.8ms | ActiveRecord: 0.6ms)
[2013-12-19 14:03:03] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-12-19 14:03:03] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started POST "/api/users" for 127.0.0.1 at 2013-12-19 14:03:37 -0500
Processing by Api::V1::UsersController#create as JSON
Completed 400 Bad Request in 1ms

ActionController::ParameterMissing (param not found: user):
app/controllers/api/v1/users_controller.rb:40:in `user_params'
app/controllers/api/v1/users_controller.rb:20:in `create'


Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack- 4.0.1/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.7ms)
Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.8ms)
Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack- 4.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (31.6ms)


EDIT #6
Here is my "real" users_controller that lives in my app and not my API. The form creates a user from this controller and NOT the API controller.

class UsersController < ApplicationController

def index
@users = User.all
@genres = Genre.all
@instruments = Instrument.all

render json: @users
end

def new
@user = User.new
end

def show
@user = User.find(params[:id])
end

def create
@user = User.new(user_params)

if @user.save
render json: @user, status: :created, location: @user
else
render json: @user.errors, status: :unprocessable_entity
end
end

private

def user_params
params.require(:user).permit(:name, :age, :location, :genre_ids => [], :instrument_ids => [])
end
end


ALSO - The User Form

<div class="row">
<div class="span6 offset3">
<%= form_for(@user) do |f| %>

<%= f.label :name %>
<%= f.text_field :name %>

<%= f.label :age %>
<%= f.text_field :age %>

<%= f.label :email %>
<%= f.text_field :email %>

<%= f.label :location %>
<%= f.text_field :location %>

<br>

<% Genre.all.each do |genre| %>
<%= check_box_tag "user[genre_ids][]", genre.id %>
<%= genre.name %><br>
<% end %>

<br>

<% Instrument.all.each do |instrument| %>
<%= check_box_tag "user[instrument_ids][]", instrument.id %>
<%= instrument.name %><br>
<% end %>

<%= f.submit "Create My Account!" %>
<% end %>
</div>
</div>

<%= users_path %>


Here is my user.rb File

class User < ActiveRecord::Base

validates :name, presence: true, length: { maximum: 50 }
has_many :generalizations
has_many :genres, through: :generalizations

has_many :instrumentations
has_many :instruments, through: :instrumentations

end


Here is what I have in my routes file:

namespace :api do
namespace :v1 do
resources :users
end
end


My POST Request

POST /api/v1/users HTTP/1.1
Host: localhost:3000
Cache-Control: no-cache

{ "user": { "name": "Sally", "age": "23", "location": "Blue York", "genre_ids": [1, 2, 3] } }

UPDATE

I changed my strong-params to be this:

def user_params
params.require(:user).permit(:name, :age, :location, :genre_ids => [], :instrument_ids => []) if params[:user]
end


So the "if" statement at the end makes the error go away, but whenever I post to my API, it gives me back "null". So this could be the same problem as before, but shown in a different way. But, at the same time, it could be progress!

Here Is The Log For The Previous Update

Started POST "/api/v1/users" for 127.0.0.1 at 2013-12-21 11:38:03 -0500
Processing by API::V1::UsersController#create as */*
(0.1ms) begin transaction
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
(0.1ms) rollback transaction
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
Rendered text template (0.0ms)
Completed 200 OK in 20ms (Views: 0.3ms | ActiveRecord: 0.6ms)


FINAL UPDATE
I was missing a few things, but the main thing that did it was that I was missing "Content-Type - application/json" as my Header.
I feel so accomplished! Thanks for all your help, everyone!

Answer

According to your code parameters in the JSON you are posting should be inside params[:user]. So the JSON should look like:

{
  "user": {
    "name": "Sally",
    "age": "23",
    "location": "Blue York",
    "genre_ids": [1, 2, 3]
  }
}
Comments