Thursday, April 21, 2016

Using Rails 5 (the API flag) and getting no route error despite route declared

Leave a Comment

This is my controller:

class Api::V1::UsersController < ApplicationController   respond_to :json    def show     respond_with User.find(params[:id])   end end 

This is my routes.rb

require 'api_constraints'  Rails.application.routes.draw do   devise_for :users   # Api definition   namespace :api, defaults: { format: :json }, constraints: { subdomain: 'api' }, path: '/' do     scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do       resources :users, :only => [:show]     end   end end 

This is my lib/api_constraints.rb

class ApiConstraints   def initialize(options)     @version = options[:version]     @default = options[:default]   end    def matches?(req)     @default || req.headers['Accept'].include?("application/vnd.myapp.v#{@version}")   end end 

I added a record to my DB as can be seen here:

[3] pry(main)> User.all   User Load (0.4ms)  SELECT "users".* FROM "users" => [#<User:0x007fbdb31079f8   id: 1,   email: "abc@test.com",   encrypted_password: "$2a$11$rvOrK1bmuuNwwc78ERxG3eCrKiUu9NTZsJ/nmirqb.3yRBHYUK69S",   reset_password_token: nil,   reset_password_sent_at: nil,   remember_created_at: nil,   sign_in_count: 0,   current_sign_in_at: nil,   last_sign_in_at: nil,   current_sign_in_ip: nil,   last_sign_in_ip: nil,   created_at: Mon, 11 Apr 2016 10:35:39 UTC +00:00,   updated_at: Mon, 11 Apr 2016 10:35:39 UTC +00:00>] 

Yet this is the error I get in my rails console:

ActionController::RoutingError (No route matches [GET] "/users/1"):  actionpack (5.0.0.beta3) lib/action_dispatch/middleware/debug_exceptions.rb:53:in `call' web-console (3.1.1) lib/web_console/middleware.rb:131:in `call_app' web-console (3.1.1) lib/web_console/middleware.rb:28:in `block in call' web-console (3.1.1) lib/web_console/middleware.rb:18:in `catch' web-console (3.1.1) lib/web_console/middleware.rb:18:in `call' actionpack (5.0.0.beta3) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call' railties (5.0.0.beta3) lib/rails/rack/logger.rb:36:in `call_app' railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `block in call' activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `block in tagged' activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:26:in `tagged' activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `tagged' railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `call' actionpack (5.0.0.beta3) lib/action_dispatch/middleware/request_id.rb:24:in `call' rack (2.0.0.alpha) lib/rack/runtime.rb:22:in `call' activesupport (5.0.0.beta3) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call' actionpack (5.0.0.beta3) lib/action_dispatch/middleware/load_interlock.rb:13:in `call' actionpack (5.0.0.beta3) lib/action_dispatch/middleware/static.rb:136:in `call' rack (2.0.0.alpha) lib/rack/sendfile.rb:111:in `call' railties (5.0.0.beta3) lib/rails/engine.rb:522:in `call' puma (3.2.0) lib/puma/configuration.rb:227:in `call' puma (3.2.0) lib/puma/server.rb:561:in `handle_request' puma (3.2.0) lib/puma/server.rb:406:in `process_client' puma (3.2.0) lib/puma/server.rb:271:in `block in run' puma (3.2.0) lib/puma/thread_pool.rb:111:in `block in spawn_thread' 

And this is what I see in my browser:

{"status":404,"error":"Not Found","exception":"#\u003cActionController::RoutingError: No route matches [GET] \"/users/1\"\u003e","traces":{"Application Trace":[],"Framework Trace":[{"id":0,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/debug_exceptions.rb:53:in `call'"},{"id":1,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:131:in `call_app'"},{"id":2,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:28:in `block in call'"},{"id":3,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:18:in `catch'"},{"id":4,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:18:in `call'"},{"id":5,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'"},{"id":6,"trace":"railties (5.0.0.beta3) lib/rails/rack/logger.rb:36:in `call_app'"},{"id":7,"trace":"railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `block in call'"},{"id":8,"trace":"activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `block in tagged'"},{"id":9,"trace":"activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:26:in `tagged'"},{"id":10,"trace":"activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `tagged'"},{"id":11,"trace":"railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `call'"},{"id":12,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/request_id.rb:24:in `call'"},{"id":13,"trace":"rack (2.0.0.alpha) lib/rack/runtime.rb:22:in `call'"},{"id":14,"trace":"activesupport (5.0.0.beta3) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'"},{"id":15,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/load_interlock.rb:13:in `call'"},{"id":16,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/static.rb:136:in `call'"},{"id":17,"trace":"rack (2.0.0.alpha) lib/rack/sendfile.rb:111:in `call'"},{"id":18,"trace":"railties (5.0.0.beta3) lib/rails/engine.rb:522:in `call'"},{"id":19,"trace":"puma (3.2.0) lib/puma/configuration.rb:227:in `call'"},{"id":20,"trace":"puma (3.2.0) lib/puma/server.rb:561:in `handle_request'"},{"id":21,"trace":"puma (3.2.0) lib/puma/server.rb:406:in `process_client'"},{"id":22,"trace":"puma (3.2.0) lib/puma/server.rb:271:in `block in run'"},{"id":23,"trace":"puma (3.2.0) lib/puma/thread_pool.rb:111:in `block in spawn_thread'"}],"Full Trace":[{"id":0,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/debug_exceptions.rb:53:in `call'"},{"id":1,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:131:in `call_app'"},{"id":2,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:28:in `block in call'"},{"id":3,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:18:in `catch'"},{"id":4,"trace":"web-console (3.1.1) lib/web_console/middleware.rb:18:in `call'"},{"id":5,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'"},{"id":6,"trace":"railties (5.0.0.beta3) lib/rails/rack/logger.rb:36:in `call_app'"},{"id":7,"trace":"railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `block in call'"},{"id":8,"trace":"activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `block in tagged'"},{"id":9,"trace":"activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:26:in `tagged'"},{"id":10,"trace":"activesupport (5.0.0.beta3) lib/active_support/tagged_logging.rb:70:in `tagged'"},{"id":11,"trace":"railties (5.0.0.beta3) lib/rails/rack/logger.rb:24:in `call'"},{"id":12,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/request_id.rb:24:in `call'"},{"id":13,"trace":"rack (2.0.0.alpha) lib/rack/runtime.rb:22:in `call'"},{"id":14,"trace":"activesupport (5.0.0.beta3) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'"},{"id":15,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/load_interlock.rb:13:in `call'"},{"id":16,"trace":"actionpack (5.0.0.beta3) lib/action_dispatch/middleware/static.rb:136:in `call'"},{"id":17,"trace":"rack (2.0.0.alpha) lib/rack/sendfile.rb:111:in `call'"},{"id":18,"trace":"railties (5.0.0.beta3) lib/rails/engine.rb:522:in `call'"},{"id":19,"trace":"puma (3.2.0) lib/puma/configuration.rb:227:in `call'"},{"id":20,"trace":"puma (3.2.0) lib/puma/server.rb:561:in `handle_request'"},{"id":21,"trace":"puma (3.2.0) lib/puma/server.rb:406:in `process_client'"},{"id":22,"trace":"puma (3.2.0) lib/puma/server.rb:271:in `block in run'"},{"id":23,"trace":"puma (3.2.0) lib/puma/thread_pool.rb:111:in `block in spawn_thread'"}]}} 

Edit 1

This is my rake routes

$ rake routes [DEPRECATION] `last_comment` is deprecated.  Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated.  Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated.  Please use `last_description` instead.                   Prefix Verb   URI Pattern                    Controller#Action         new_user_session GET    /users/sign_in(.:format)       devise/sessions#new             user_session POST   /users/sign_in(.:format)       devise/sessions#create     destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy            user_password POST   /users/password(.:format)      devise/passwords#create        new_user_password GET    /users/password/new(.:format)  devise/passwords#new       edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit                          PATCH  /users/password(.:format)      devise/passwords#update                          PUT    /users/password(.:format)      devise/passwords#update cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel        user_registration POST   /users(.:format)               devise/registrations#create    new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new   edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit                          PATCH  /users(.:format)               devise/registrations#update                          PUT    /users(.:format)               devise/registrations#update                          DELETE /users(.:format)               devise/registrations#destroy                 api_user GET    /users/:id(.:format)           api/v1/users#show {:format=>:json, :subdomain=>"api"} 

Edit 2

This is my application controller:

class ApplicationController < ActionController::API end 

Edit 3

This is my users_controller_spec.rb test that actually passes:

require 'rails_helper'  describe Api::V1::UsersController do   before(:each) { request.headers['Accept'] = "application/vnd.myapp.v1" }    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 user 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 

This is the result:

$ rspec spec/controllers DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead). (called from <top (required)> at /myapp/spec/controllers/api/v1/users_controller_spec.rb:3) DEPRECATION WARNING: ActionController::TestCase HTTP request methods will accept only keyword arguments in future Rails versions.  Examples:  get :show, params: { id: 1 }, session: { user_id: 1 } process :update, method: :post, params: { id: 1 }  (called from block (3 levels) in <top (required)> at /myapp/spec/controllers/api/v1/users_controller_spec.rb:9) DEPRECATION WARNING: ActionController::TestCase HTTP request methods will accept only keyword arguments in future Rails versions.  Examples:  get :show, params: { id: 1 }, session: { user_id: 1 } process :update, method: :post, params: { id: 1 }  (called from block (3 levels) in <top (required)> at /myapp/spec/controllers/api/v1/users_controller_spec.rb:9) .DEPRECATION WARNING: ActionController::TestCase HTTP request methods will accept only keyword arguments in future Rails versions.  Examples:  get :show, params: { id: 1 }, session: { user_id: 1 } process :update, method: :post, params: { id: 1 }  (called from block (3 levels) in <top (required)> at /myapp/spec/controllers/api/v1/users_controller_spec.rb:9) DEPRECATION WARNING: ActionController::TestCase HTTP request methods will accept only keyword arguments in future Rails versions.  Examples:  get :show, params: { id: 1 }, session: { user_id: 1 } process :update, method: :post, params: { id: 1 }  (called from block (3 levels) in <top (required)> at /myapp/spec/controllers/api/v1/users_controller_spec.rb:9) .  Finished in 0.41411 seconds (files took 3.33 seconds to load) 2 examples, 0 failures 

1 Answers

Answers 1

The problem is that your route has a constraint requiring a subdomain of api. So http://api.lvh.me:3000/users/1.json will work, but not http://localhost:3000/users/1.json or http://lvh.me:3000/users/1.json.

You should change your Ajax call to use an api subdomain. You can also confirm this by writing a request test (not a controller test), and see that it gets a 200 when using an api subdomain, and a 404 otherwise.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment