Reputation: 821
I am following Michael Hartl's tutorial, chapter 10. Test UsersControllerTest#test_should_redirect_edit_when_logged_in_as_wrong_user
fails when trying to do get edit_user_path(@user)
.
get edit_user_path(@user)
ActionController::UrlGenerationError: No route matches {:action=>"/users/762146111/edit", :controller=>"users"}
from /Users/cello/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/actionpack-5.1.4/lib/action_dispatch/journey/formatter.rb:55:in `generate'
However:
Rails.application.routes.recognize_path '/users/762146111/edit', method: :get
=> {:controller=>"users", :action=>"edit", :id=>"762146111"}
Below is the code that might have a bug (Rails 5.1.4).
routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
post 'signup', to: 'users#create'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get 'sessions/new'
resources :users
end
users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
@user = users(:michael)
@other_user = users(:archer)
end
test 'should redirect edit when logged in as wrong user' do
log_in_as(@other_user)
get edit_user_path(@user)
assert flash.empty?
assert_redirected_to root_url
end
end
users_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def edit
@user = User.find(params[:id])
end
private
def logged_in_user
unless logged_in?
flash[:danger] = 'Please log in.'
redirect_to login_url
end
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end
Upvotes: 0
Views: 224
Reputation: 4435
The tutorial is defining an Integration Test (inherits from ActionDispatch::IntegrationTest
), whereas your above code is defining a Controller Test (inherits from ActionController::TestCase
).
get :edit, ...
is the correct syntax for a controller test, because it bypasses URL recognition and directly specifies the :action
. This is confusing, and is one of several reasons that controller tests are now discouraged in favour of integration tests, which is probably what you want to create.
To do so, change:
class UsersControllerTest < ActionController::TestCase
to:
class UsersControllerTest < ActionDispatch::IntegrationTest
(Note the tutorial, somewhat confusingly, uses ActionDispatch::IntegrationTest
as the base class both for tests it puts in tests/integration/
and those it puts in tests/controllers/
.)
Upvotes: 1
Reputation: 84
You can not use direct url with 'get' method in spec.
In your spec instead of
get edit_user_path(@user)
use
get :edit, params: { id: @user.id }
the same with
patch user_path(@user)
use patch :update
instead
Upvotes: 0