Michael Hartle Chapter 5: "No route matches" error - ruby-on-rails

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

Related

Rails Spec Controller Test failing with custom route

Rails 5.1
RSpec 3.6
I have a Controller:
class SessionController < ApplicationController
def new
end
end
A custom route:
get 'login' => 'sessions#new'
RSpec Test:
require 'rails_helper'
RSpec.describe SessionController, type: :controller do
describe "GET #new" do
before do
routes.draw { get "login" => "sessions#new" }
end
it "returns http success" do
get :login
expect(response).to have_http_status(:success)
end
end
end
and get error:
ActionController::UrlGenerationError: No route matches {:action=>"login", :controller=>"session"}
So "get" within a controller test seems always map to the action not the route. What should i do to get this test run? thanks in advance.
ActionController::UrlGenerationError: No route matches
{:action=>"login", :controller=>"session"}
Your controller name is SessionController, so your route should be
get 'login' => 'session#new' not get 'login' => 'sessions#new'
require 'rails_helper'
RSpec.describe SessionController, type: :controller do
describe "GET #new" do
before do
routes.draw { get "login" => "session#new" }
end
it "returns http success" do
get :login
expect(response).to have_http_status(:success)
end
end
end
Change it in your routes.rb as well.
When you are writing tests and you use the methods get, post, delete, etc., those methods assume that any parameter you pass them is the name of an action within the controller being tested. So, this works:
get :new
because it generates url_for(:controller => :sessions, :action => :new).
This doesn't work:
get '/login'
because it generates url_for(:controller => :sessions, :action => '/login').

ActionController::UrlGenerationError: No route matches action and controller

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.

ActionController::UrlGenerationError - with route defined and action in controller, still getting error for no route

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) }

How to test a controller action that does not exist?

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.

Rspec "No route matches" error

I am attempting to test my sessions_controller in Rails 3 app with rspec, but keep coming across this error when I run rspec on my sessions_controller_spec.rb:
ActionController::RoutingError:
No route matches {:controller=>"sessions", :action=>"create"}
Here are all the relevant files:
routes.rb
match 'event' => 'event#create', via: [:post]
match 'event/agenda' => 'event#agenda', via: [:get]
match 'testLogin' => 'application#test_login', via: [:get]
post 'session' => 'session#create'
sessions_controller.rb
class SessionsController < ApplicationController
def create
#MY CODE HERE
end
end
sessions_controller_spec.rb
require 'spec_helper'
describe SessionsController, :type => :controller do
describe "POST #create" do
context "invalid params" do
it "returns a response with status failed if all required parameters are not passed in" do
post "create"
response.body.status.should eq("failed")
end
end
end
end
If there's any other info I can provide to help let me know. Thanks a lot!
post 'session' => 'session#create'
Your route definition is looking for a SessionController, but you have defined a SessionsController. Fix your route.
post 'session' => 'sessions#create'

Resources