Reputation: 2055
I am trying to create an api for my rails application in the Controllers folder I have created the following folder structure
controllers > api > v1
my routes look something like this require 'api_constraints'
MyApp::Application.routes.draw do
devise_for :users
resources :users
......
other resources and matching for the standard application
......
# Api definition
namespace :api, defaults: { format: :json },constraints: { subdomain: 'api' }, path: '/' do
scope module: :v1,constraints: ApiConstraints.new(version: 1, default: true) do
resources :sessions, :only => [:create]
resources :users, :only => [:show]
end
end
end
I get the same error in both my sessions and users controllers. I will just post the User controller because it's shorter
class Api::V1::UsersController < ApiController
respond_to :json
def show
respond_with User.find(params[:id])
end
end
Then my tests are
require 'spec_helper'
describe Api::V1::UsersController do
describe "GET #show" do
before(:each) do
@user = FactoryGirl.create :user
get :show, id: @user.id, format: :json
end
it "returns the information about a reporter on a hash" do
user_response = JSON.parse(response.body, symbolize_names: true)
expect(user_response[:email]).to eql @user.email
end
it { should respond_with 200 }
end
end
And the output from the test is
4) Api::V1::UsersController GET #show Failure/Error: get :show, id: @user.id, format: :json ArgumentError: wrong number of arguments (0 for 1)
Two problems are 1) for some reason the id isn't getting sent to the api action 2) I'm not sure how to get to the api. I thought it should be api.localhost:3000/users/1
Thanks in advance for any help
Update This is the output for rake routes
api_sessions POST /sessions(.:format) api/v1/sessions#create {:format=>:json, :subdomain=>"api"}
api_user GET /users/:id(.:format) api/v1/users#show {:format=>:json, :subdomain=>"api"}
Update 2 This looks like a duplicate for wrong number of arguments (0 for 1) while create my user
Unfortunately the solution to this post isn't an option for me. I can't remove Devise because the User model is shared in a standard Web rails application and the api portion of the application
Update 3 I was looking at other ways of having a API with a standard app, and using devise with doorkeeper seems like a better solution than token authentication. After getting it setup I am back in the same situation of
wrong number of arguments (0 for 1)
In the server output I see the following output. This is with a valid user id.
Started GET "/api/v1/users/1" for ::1 at 2015-07-27 20:52:09 +0100
Processing by Api::V1::UsersController#show as */*
Parameters: {"id"=>"1"}
Geokit is using the domain: localhost
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Completed 500 Internal Server Error in 21ms
ArgumentError (wrong number of arguments (0 for 1)): app/controllers/api/v1/users_controller.rb:5:in `show'
With an invalid id I get this output
Started GET "/api/v1/users/134" for ::1 at 2015-07-27 20:55:36 +0100
Processing by Api::V1::UsersController#show as */*
Parameters: {"id"=>"134"}
Geokit is using the domain: localhost
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 134]]
Completed 500 Internal Server Error in 6ms
NoMethodError (undefined method `api_error' for
#<Api::V1::UsersController:0x007fc5a17bf098>): app/controllers/api_controller.rb:23:in `not_found'
Update 4 After inserting some debug statements the ID is being passed through to the controller action and the user is being retrieved from the database.
The issue is with
respond_with User.find(params[:id])
rails is unable to serialize the user. I have tried replacing User with another model that does not have Devise enabled and it can serialize the model. I'm not sure why devise is causing an issue here.
Upvotes: 0
Views: 1740
Reputation: 2055
This took a while for me to find out the solution and you can trace what I was thinking from the post above.
In the end, I traced the issue to that a model using devise cannot be serialized like a normal model. You can't just use
respont_with User.first
or anything like that. Devise disables the default to_json method for activerecord.
A lot of solutions talked about overwriting the to_json method or using JBuilder in the model. I didn't like this because it would restrict the possible attributes you could return.
After looking at the documentation for to_json I decided that simply passing the attributes I wanted in the options was exactly what I wanted.
def show
respond_with User.find(params[:id]).as_json(only: [:id, :name])
end
Upvotes: 0
Reputation: 454
1: Verify in console that FactoryGirl is able to properly return a user object created from your user factory so that isn't nil in your get request.
2: Run rake routes to verify what the API routes its generating look like. I'm assuming if you haven't previously set this up, you will need to edit your hosts file or use something like pow on mac or nginx w/ dnsmasq on Linux to enable subdomain support in your local development environment. Then manually test your API controller by whatever subdomain you configured like http://api.myappname.dev/api/v1/users/1.json to make sure you can see it returing a valid JSON response from that URL.
A little bit cleaner example of API namespacing in routes:
namespace :api, :path => "", :constraints => {:subdomain => "api"} do
namespace :v1, defaults: { format: 'json' } do
...
end
end
Upvotes: 1