Reputation: 7832
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
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