Steve Gattuso
Steve Gattuso

Reputation: 7832

RSpec cannot find route for nested resource

I'm dealing with a seemingly strange issue while trying to run unit tests on a nested resources controller. Here's my setup:

routes.rb:

Rails.application.routes.draw do
  scope module: 'api' do
    namespace :v1 do
      resources :users do
        resources 'item-configurations',
          controller: :item_configuration,
            as: :item_configurations,
            on: :member
      end
    end
  end
end

app/controllers/api/v1/item_configurations_controller.rb:

module Api::V1                              
  class ItemConfigurationsController < ApplicationController
    def show
      @user = authorize User.find(params[:user_id])      
      @item_configuration = authorize @user.item_configurations.find(params[:id])

      success @item_configuration
    end
  end
end

and finally, spec/controllers/api/v1/item_configurations_controller_spec.rb:

require 'rails_helper'

describe Api::V1::ItemConfigurationsController do
  describe '#show' do
    it 'renders an item configuration' do
      user = FactoryGirl.create(:user)
      configuration = FactoryGirl.create(:item_configuration)

      get :show, params: {user_id: user.id, id: configuration.id}
      expect(response.status).to equal(200)
    end
  end
end

When I make a request to /users/1/item-configurations/4 I'm able to get a response, just as I'd expect. The issue comes from when I run rspec, I get the following error:

  1) Api::V1::ItemConfigurationsController#show renders an item configuration
     Failure/Error: get :show, params: {user_id: user.id, id: configuration.id}

     ActionController::UrlGenerationError:
       No route matches {:action=>"show", :controller=>"api/v1/item_configurations", :id=>1, :user_id=>1}

Normally these errors arise when a parameter is missing from the request, but in this case everything appears to be there (both user_id and id). I've also tried this on other routes on the controller (#index also works when sent a GET but does not work in rspec), adding a format: :json param, etc. but nothing seems to solve it.

Am I crazy or is there something simple I'm missing here?

Upvotes: 1

Views: 1251

Answers (1)

shlajin
shlajin

Reputation: 1576

Well, apart from the typo controller: :item_configuration (singular, while controller is plural) in your routes you specify on parameter on resources. It seems to be it acts like a constraint on resources, rather than as a "type" of interaction.

From console:

app.url_for({:action=>"show", :controller=>"api/v1/item_configurations", :id=>"2", :user_id=>"1"})
=> ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"api/v1/item_configurations", :id=>"2", :user_id=>"1"}
app.url_for({:action=>"show", :controller=>"api/v1/item_configurations", :id=>"2", :user_id=>"1", on: :member})
=> "http://www.example.com/v1/users/1/item_configurations/2"

Therefore, use member block in routes to achieve desired behaviour:

...
resources :users do
  member do
     resources :configuration_items 
  end
end
...

Upvotes: 4

Related Questions