I couldn't find a solution in the other relative questions, so I'm asking my own.
The problem is pretty straightforward. This is the error I'm getting:
Failure/Error: get 'api/v2/special_keys#show'
ActionController::UrlGenerationError:
No route matches {:action=>"api/v2/special_keys#show", :controller=>"api/v2/special_keys"}
This is my routes.rb:
resources :special_keys, only: [] do
collection do
get '', to: 'special_keys#show'
end
end
This is the output from rake routes:
GET /api/v2/special_keys(.:format) api/v2/special_keys#show {:format=>"json"}
And my spec:
require 'rails_helper'
describe Api::V2::SpecialKeysController do
describe 'GET #show' do
it 'gets the policy and signature' do
get '/api/v2/special_keys'
expect(response.status).to eql 200
end
end
end
Try to rewrite your test as:
require 'rails_helper'
describe Api::V2::SpecialKeysController do
describe 'GET #show' do
it 'gets the policy and signature' do
get '/api/v2/special_keys', {format: :json}
expect(response.status).to eql 200
end
end
end
Try:
resource :special_keys, only: [:show]
The singular tells the app, that there is only one. So it will only generate a show action that needs no id and no indexaction at all.
Related
I have such code in my routes.rb:
Rails.application.routes.draw do
authorized = ->(request) { request.session[:user_id].present? }
not_authorized = ->(request) { request.session[:user_id].blank? }
constraints authorized do
resources :users
end
constraints not_authorized do
get 'login' => 'auth#login_page'
post 'login' => 'auth#create_session'
get '*unmatched_route', to: 'auth#login_page'
root 'auth#login_page'
end
end
And I have such users_routing_spec.rb file:
require "rails_helper"
RSpec.describe UsersController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(:get => "/users").to route_to("users#index")
end
end
end
This test fails as it routes to 'auth#login_page' because there is no user_id
in session.
How can I call auth#create_session in advance to the expectation?
There is no request or #request object and I also can't make a manual request to 'auth#create_session'
I'm getting the following error in RSpec when running my schools_controller_spec.rb test:
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"schools"}
What's puzzling me is that I have the routes configured, and the action defined in the appropriate controller. I'm not getting this error for other tests in the spec, such as 'GET #index', etc. Running Rails 4.2 with RSpec/Capybara.
Here's the routes.rb:
Rails.application.routes.draw do
root to: 'pages#home', id: 'home'
resources :users
resources :schools
resource :session, only: [:new, :create, :destroy]
match '/home', to: 'pages#home', via: 'get', as: 'home_page'
end
rake routes returns:
schools GET /schools(.:format) schools#index
POST /schools(.:format) schools#create
new_school GET /schools/new(.:format) schools#new
edit_school GET /schools/:id/edit(.:format) schools#edit
school GET /schools/:id(.:format) schools#show
PATCH /schools/:id(.:format) schools#update
PUT /schools/:id(.:format) schools#update
DELETE /schools/:id(.:format) schools#destroy
There's the route defined on the fifth line, as schools#show.
The schools_controller.rb:
class SchoolsController < ApplicationController
before_action :require_signin
before_filter :admin_only, except: :index, :show
def index
#schools = School.all
end
def show
# code pending
end
private
def admin_only
unless current_user.admin?
redirect_to :back, alert: "Access denied."
end
end
end
The link to the individual school seems to be properly defined in the view helper (_school.html.haml):
%li#schools
= link_to school.name, school
= school.short_name
= school.city
= school.state
and looking at the front-end HTML confirms it's working correctly. I can see, for example: Community College of the Air Force. When I click that link the page shows the following in the debug dump:
--- !ruby/hash:ActionController::Parameters
controller: schools
action: show
id: '1'
Finally, for good measure, here's the spec file (schools_controller_spec.rb):
require 'rails_helper'
describe SchoolsController, type: :controller do
# specs omitted for other actions
describe 'GET #show' do
context "when not signed in" do
it "returns a 302 redirect code" do
get :show
expect(response.status).to eq 302
end
it "redirects to the signin page" do
get :show
expect(response).to redirect_to new_session_path
end
end
context "when signed in as user" do
before :each do
#user = double(:user)
allow(controller).to receive(:current_user).and_return #user
#school = create(:school)
end
it "assigns the school to the #school variable" do
get :show
expect(assigns(:school)).to eq #school
end
end
end
end
The route appears in rake routes. The method is defined in the appropriate controller. There don't appear to be any silly naming errors (e.g. plural/singular). The spec doesn't appear to have any issues routing GET #index or other routes for example. Everything works exactly as expected in the browser.
So why do I keep getting the "no route matches" error when I run my controller spec?
This is because the show action is expecting an id which you currently aren't passing. Replace:
get :show
With this:
get :show, id: school.id
The above assumes you have a school variable, perhaps a let in a before block?
let(:school) { create(:school) }
I am using Rails 4.0.8. When I ran bundle exec rspec spec/, here's the error I got from the tutorial (http://www.railstutorial.org/book/filling_in_the_layout):
Pending: StaticPagesHelper add some examples to (or delete)
/Users/Desktop/sample_app/spec/helpers/static_pages_helper_spec.rb
# No reason given
# ./spec/helpers/static_pages_helper_spec.rb:14
Failures:
1) StaticPagesController GET '...' returns http success
Failure/Error: get '...'
ActionController::UrlGenerationError:
No route matches {:action=>"...", :controller=>"static_pages"}
# ./spec/controllers/static_pages_controller_spec.rb:7:in `block (3 levels) in '
Finished in 0.20849 seconds 19 examples, 1 failure, 1 pending
Failed examples:
rspec ./spec/controllers/static_pages_controller_spec.rb:6 #
StaticPagesController GET '...' returns http success
Here is my route.rb file:
SampleApp::Application.routes.draw do
resources :users
root to: 'static_pages#home'
match '/signup', to: 'users#new', via: 'get'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
end
Here is my static_pages_helper_spec.rb file:
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# the StaticPagesHelper. For example:
#
# describe StaticPagesHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# helper.concat_strings("this","that").should == "this that"
# end
# end
# end describe StaticPagesHelper do pending "add some examples to (or delete) #{__FILE__}" end
Here is my static_pages_controller_spec.rb file:
require 'spec_helper'
describe StaticPagesController do
describe "GET '...'" do
it "returns http success" do
get '...'
response.should be_success
end
end
end
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
end
def help
end
def about
end
def contact
end
end
I wonder whether I'm getting the error because my version is not compatible with his tutorial. Should I be looking at this tutorial instead http://rails-3-2.railstutorial.org/book/filling_in_the_layout#sec-rails_routes?
Your static_pages_controller_spec has
describe "GET '...'" do
it "returns http success" do
get '...'
response.should be_success
end
end
The "..." is nonsense in this context and the tutorial probably included it as a "specimen" entry.
Comment out the above lines, or replace "..." with a real method in your static_pages_controller.rb. You probably have an index method so you could do...
describe "GET index" do
it "returns http success" do
get :index
response.should be_success
end
end
Cheers
There are only two actions accessible in the ProductsController:
# /config/routes.rb
RailsApp::Application.routes.draw do
resources :products, only: [:index, :show]
end
Tests are set up accordingly:
# /spec/controllers/products_controller_spec.rb
require 'spec_helper'
describe ProductsController do
before do
#product = Product.gen
end
describe "GET index" do
it "renders the index template" do
get :index
expect(response.status).to eq(200)
expect(response).to render_template(:index)
end
end
describe "GET show" do
it "renders the show template" do
get :show, id: #product.id
expect(response.status).to eq(200)
expect(response).to render_template(:show)
end
end
end
How would you test that the other CRUD actions are not accessible? This might change in the future so the tests will ensure any configuration change will be noticed.
I found the be_routable matcher which looks promising to cover the test case.
I recommend this post by Dave Newton which describes when and why to test controller actions.
Here is what I came up with:
context "as any user" do
describe "not routable actions" do
it "rejects routing for :new" do
expect(get: "/products/new").not_to be_routable
end
it "rejects routing for :create" do
expect(post: "/products").not_to be_routable
end
it "rejects routing for :edit" do
expect(get: "/products/#{#product.id}/edit").not_to be_routable
end
it "rejects routing for :update" do
expect(put: "/products/#{#product.id}").not_to be_routable
end
it "rejects routing for :destroy" do
expect(delete: "/products/#{#product.id}").not_to be_routable
end
end
end
However one test fails:
Failure/Error: expect(get: "/products/new").not_to be_routable
expected {:get=>"/products/new"} not to be routable,
but it routes to {:action=>"show", :controller=>"products", :id=>"new"}
Please feel free to add your own solution if you follow a totally different approach to test non-existing routes.
I have simplified an issue I am having to the following
I have a route that looks like this
namespace :client do
resources :thing, :only => [:index]
end
and the simple rspec test
describe Client::ThingController do
describe "GET 'index'" do
it "returns http success" do
get 'index'
response.should be_success
end
end
end
However what I'd like to do is alter the url I use to access the resource from
/client/thing.json
to
/api/client/v1/thing.json
1) How do I update my routes and rspec?
If I then wanted to parameterise the uri such that I could extract the api_version
/api/client/[api_version]/thing.json
2) How would this effect my routes and simple rspec test?
I'd previously tried what #Mori had suggested before I had posted but without having the multiple routes as proposed, I should have mentioned that in the original post.
What I eventually got that worked is:
1) In routes.rb I added
match "api/client/:api_version/thing" => 'client/thing#index'
NOTE: The missing leading '/' ie match "/api/... => match "api/... it seems to make all the difference to rspec.
2) And in my rspec thing_controller_spec.rb I now have this
describe Client::ThingController do
describe "GET 'index'" do
it "returns http success" do
get 'index', :api_version => 'v1'
response.should be_success
end
end
end
I was close before but it was the leading '/' in routes.rb that broke me even though I could navigate to the url in a browser.