简体   繁体   中英

Wrong number of arguments 0 for 1 unable to serialize model using devise

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM