rake routes is duplicating api_version routes #50

Closed
sricc opened this Issue Aug 16, 2013 · 6 comments

Comments

Projects
None yet
3 participants
@sricc

sricc commented Aug 16, 2013

I am getting duplicate routes within a rake routes when resources are within an api_version block.

My routes are setup as follows

MyApp::Application.routes.draw do
  root :to => redirect("/signin")

  # Devise
  devise_for :users, :skip => [:sessions]
  as :user do
    get 'signin'     => 'home#index',              :as => :new_user_session
    post 'signin'    => 'devise/sessions#create',  :as => :user_session
    delete 'signout' => 'devise/sessions#destroy', :as => :destroy_user_session
  end

  # API
  api_version(:module => 'api/v1', :header => {:name => 'Accept', :value => "application/vnd.domain.com; version=1"}, :default => true, :defaults => {:format => :json}) do

      get 'things' => 'thing#index'
      resources 'thing', except: :index

  end
end

When I run rake routes this is my output

 Prefix Verb   URI Pattern                    Controller#Action
                root GET    /                              redirect(301, /signin)
       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
    new_user_session GET    /signin(.:format)              home#index
        user_session POST   /signin(.:format)              devise/sessions#create
destroy_user_session DELETE /signout(.:format)             devise/sessions#destroy
              things GET    /things(.:format)              api/v1/thing#index {:format=>:json}
         thing_index POST   /thing(.:format)               api/v1/thing#create {:format=>:json}
           new_thing GET    /thing/new(.:format)           api/v1/thing#new {:format=>:json}
          edit_thing GET    /thing/:id/edit(.:format)      api/v1/thing#edit {:format=>:json}
               thing GET    /thing/:id(.:format)           api/v1/thing#show {:format=>:json}
                     PATCH  /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     PUT    /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     DELETE /thing/:id(.:format)           api/v1/thing#destroy {:format=>:json}
                     GET    /things(.:format)              api/v1/thing#index {:format=>:json}
                     POST   /thing(.:format)               api/v1/thing#create {:format=>:json}
                     GET    /thing/new(.:format)           api/v1/thing#new {:format=>:json}
                     GET    /thing/:id/edit(.:format)      api/v1/thing#edit {:format=>:json}
                     GET    /thing/:id(.:format)           api/v1/thing#show {:format=>:json}
                     PATCH  /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     PUT    /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     DELETE /thing/:id(.:format)           api/v1/thing#destroy {:format=>:json}

As you can see, the first set of routes are:

              things GET    /things(.:format)              api/v1/thing#index {:format=>:json}
         thing_index POST   /thing(.:format)               api/v1/thing#create {:format=>:json}
           new_thing GET    /thing/new(.:format)           api/v1/thing#new {:format=>:json}
          edit_thing GET    /thing/:id/edit(.:format)      api/v1/thing#edit {:format=>:json}
               thing GET    /thing/:id(.:format)           api/v1/thing#show {:format=>:json}
                     PATCH  /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     PUT    /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     DELETE /thing/:id(.:format)           api/v1/thing#destroy {:format=>:json}

and the second set of routes are:

                     GET    /things(.:format)              api/v1/thing#index {:format=>:json}
                     POST   /thing(.:format)               api/v1/thing#create {:format=>:json}
                     GET    /thing/new(.:format)           api/v1/thing#new {:format=>:json}
                     GET    /thing/:id/edit(.:format)      api/v1/thing#edit {:format=>:json}
                     GET    /thing/:id(.:format)           api/v1/thing#show {:format=>:json}
                     PATCH  /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     PUT    /thing/:id(.:format)           api/v1/thing#update {:format=>:json}
                     DELETE /thing/:id(.:format)           api/v1/thing#destroy {:format=>:json}

This doesn't happen if I put the same resource in a namespace or just as a regular route only within api_version.

Am I doing something wrong or is this a bug?

Thanks.

@bploetz

This comment has been minimized.

Show comment
Hide comment
@bploetz

bploetz Aug 16, 2013

Owner

It actually looks like the :default => true is causing that. Observe:

 api_version(:module => 'api/v1', :header => {:name => 'Accept', :value => "application/vnd.domain.com; version=1"}, :default => true, :defaults => {:format => :json}) do
    resources :foos
  end
> bundle exec rake routes
  Prefix Verb   URI Pattern              Controller#Action
    foos GET    /foos(.:format)          api/v1/foos#index {:format=>:json}
         POST   /foos(.:format)          api/v1/foos#create {:format=>:json}
 new_foo GET    /foos/new(.:format)      api/v1/foos#new {:format=>:json}
edit_foo GET    /foos/:id/edit(.:format) api/v1/foos#edit {:format=>:json}
     foo GET    /foos/:id(.:format)      api/v1/foos#show {:format=>:json}
         PATCH  /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         PUT    /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         DELETE /foos/:id(.:format)      api/v1/foos#destroy {:format=>:json}
         GET    /foos(.:format)          api/v1/foos#index {:format=>:json}
         POST   /foos(.:format)          api/v1/foos#create {:format=>:json}
         GET    /foos/new(.:format)      api/v1/foos#new {:format=>:json}
         GET    /foos/:id/edit(.:format) api/v1/foos#edit {:format=>:json}
         GET    /foos/:id(.:format)      api/v1/foos#show {:format=>:json}
         PATCH  /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         PUT    /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         DELETE /foos/:id(.:format)      api/v1/foos#destroy {:format=>:json}
 api_version(:module => 'api/v1', :header => {:name => 'Accept', :value => "application/vnd.domain.com; version=1"}, :defaults => {:format => :json}) do                                                                                                                                           
    resources :foos
  end
> bundle exec rake routes
  Prefix Verb   URI Pattern              Controller#Action
    foos GET    /foos(.:format)          api/v1/foos#index {:format=>:json}
         POST   /foos(.:format)          api/v1/foos#create {:format=>:json}
 new_foo GET    /foos/new(.:format)      api/v1/foos#new {:format=>:json}
edit_foo GET    /foos/:id/edit(.:format) api/v1/foos#edit {:format=>:json}
     foo GET    /foos/:id(.:format)      api/v1/foos#show {:format=>:json}
         PATCH  /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         PUT    /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         DELETE /foos/:id(.:format)      api/v1/foos#destroy {:format=>:json}

The way defaulting works is that it actually puts in another scope into your routes to handle the case when no version is requested:

https://github.com/bploetz/versionist/blob/master/lib/versionist/routing.rb#L64

Unfortunately rake routes doesn't show you the advanced constraints info (http://guides.rubyonrails.org/routing.html#advanced-constraints) which is where versionist hooks in to do it's thing. If it did, you'd see one is the actual version handler, the other is the default handler.

Owner

bploetz commented Aug 16, 2013

It actually looks like the :default => true is causing that. Observe:

 api_version(:module => 'api/v1', :header => {:name => 'Accept', :value => "application/vnd.domain.com; version=1"}, :default => true, :defaults => {:format => :json}) do
    resources :foos
  end
> bundle exec rake routes
  Prefix Verb   URI Pattern              Controller#Action
    foos GET    /foos(.:format)          api/v1/foos#index {:format=>:json}
         POST   /foos(.:format)          api/v1/foos#create {:format=>:json}
 new_foo GET    /foos/new(.:format)      api/v1/foos#new {:format=>:json}
edit_foo GET    /foos/:id/edit(.:format) api/v1/foos#edit {:format=>:json}
     foo GET    /foos/:id(.:format)      api/v1/foos#show {:format=>:json}
         PATCH  /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         PUT    /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         DELETE /foos/:id(.:format)      api/v1/foos#destroy {:format=>:json}
         GET    /foos(.:format)          api/v1/foos#index {:format=>:json}
         POST   /foos(.:format)          api/v1/foos#create {:format=>:json}
         GET    /foos/new(.:format)      api/v1/foos#new {:format=>:json}
         GET    /foos/:id/edit(.:format) api/v1/foos#edit {:format=>:json}
         GET    /foos/:id(.:format)      api/v1/foos#show {:format=>:json}
         PATCH  /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         PUT    /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         DELETE /foos/:id(.:format)      api/v1/foos#destroy {:format=>:json}
 api_version(:module => 'api/v1', :header => {:name => 'Accept', :value => "application/vnd.domain.com; version=1"}, :defaults => {:format => :json}) do                                                                                                                                           
    resources :foos
  end
> bundle exec rake routes
  Prefix Verb   URI Pattern              Controller#Action
    foos GET    /foos(.:format)          api/v1/foos#index {:format=>:json}
         POST   /foos(.:format)          api/v1/foos#create {:format=>:json}
 new_foo GET    /foos/new(.:format)      api/v1/foos#new {:format=>:json}
edit_foo GET    /foos/:id/edit(.:format) api/v1/foos#edit {:format=>:json}
     foo GET    /foos/:id(.:format)      api/v1/foos#show {:format=>:json}
         PATCH  /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         PUT    /foos/:id(.:format)      api/v1/foos#update {:format=>:json}
         DELETE /foos/:id(.:format)      api/v1/foos#destroy {:format=>:json}

The way defaulting works is that it actually puts in another scope into your routes to handle the case when no version is requested:

https://github.com/bploetz/versionist/blob/master/lib/versionist/routing.rb#L64

Unfortunately rake routes doesn't show you the advanced constraints info (http://guides.rubyonrails.org/routing.html#advanced-constraints) which is where versionist hooks in to do it's thing. If it did, you'd see one is the actual version handler, the other is the default handler.

@sricc

This comment has been minimized.

Show comment
Hide comment
@sricc

sricc Aug 16, 2013

Ah, ok, I see. Maybe it would be a good idea to make a note of this in the README docs.

Thanks!

sricc commented Aug 16, 2013

Ah, ok, I see. Maybe it would be a good idea to make a note of this in the README docs.

Thanks!

@bploetz

This comment has been minimized.

Show comment
Hide comment
@bploetz

bploetz Aug 16, 2013

Owner

Yeah I will note this in the README. Frankly I never noticed it until you pointed it out. :-) Thanks!

Owner

bploetz commented Aug 16, 2013

Yeah I will note this in the README. Frankly I never noticed it until you pointed it out. :-) Thanks!

@bploetz bploetz closed this Aug 16, 2013

@sricc

This comment has been minimized.

Show comment
Hide comment
@sricc

sricc Aug 16, 2013

Glad to help!

sricc commented Aug 16, 2013

Glad to help!

@thewatts

This comment has been minimized.

Show comment
Hide comment
@thewatts

thewatts Dec 13, 2016

I seem to be having this same issue, but I'm not declaring the default: true configuration. Instead, I'm adding an Accept header.

Has Duplicates (in a different scope)

namespace :api do
  api_version(module: 'V2', header: { name: 'Accept', value: 'application/vnd.api+json' }, path: { value: 'v2' }) do
    resources :account_lists, only: [:index, :show, :update] do
$ bundle exec rake routes

/api/account_lists
/api/v2/account_lists

Doesn't have Duplicates

namespace :api do
  api_version(module: 'V2', path: { value: 'v2' } do
    resources :account_lists, only: [:index, :show, :update] do
$ bundle exec rake routes

/api/v2/account_lists

I see here that you can specify multiple versions - but honestly I'm not sure where in that code example a second version is being declared.

Thanks for your hard work on this gem!

I seem to be having this same issue, but I'm not declaring the default: true configuration. Instead, I'm adding an Accept header.

Has Duplicates (in a different scope)

namespace :api do
  api_version(module: 'V2', header: { name: 'Accept', value: 'application/vnd.api+json' }, path: { value: 'v2' }) do
    resources :account_lists, only: [:index, :show, :update] do
$ bundle exec rake routes

/api/account_lists
/api/v2/account_lists

Doesn't have Duplicates

namespace :api do
  api_version(module: 'V2', path: { value: 'v2' } do
    resources :account_lists, only: [:index, :show, :update] do
$ bundle exec rake routes

/api/v2/account_lists

I see here that you can specify multiple versions - but honestly I'm not sure where in that code example a second version is being declared.

Thanks for your hard work on this gem!

@bploetz

This comment has been minimized.

Show comment
Hide comment
@bploetz

bploetz Dec 14, 2016

Owner

@thewatts Weird. Can you include your entire routes file and the entire output of rake routes? Also, what version of Rails and versionist are you using?

Owner

bploetz commented Dec 14, 2016

@thewatts Weird. Can you include your entire routes file and the entire output of rake routes? Also, what version of Rails and versionist are you using?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment