Testing overridden Devise controllers – "No route matches" - ruby-on-rails

I ran rails g devise:controllers users and my routes look like
devise_for :users, controllers: {
sessions: 'sessions'
}
I have a app/controllers/users/sessions_controller that I want to test. My routes look like:
$ rake routes
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) sessions#new
user_session POST /users/sign_in(.:format) sessions#create
I set up my test like this:
# test/controllers/users/sessions_controller_test.rb
require 'test_helper'
class SessionsControllerTest < ActionController::TestCase
tests Users::SessionsController
test "sign in sanity check" do
user = users(:one)
post :create, email: user.email, password: 'password'
assert_response :success
end
end
Which fails with the error:
ActionController::UrlGenerationError: No route matches {:action=>"create", :controller=>"users/sessions", :email=>"one#example.com", :password=>"password"}
How do I correctly POST to the URL I want? I've tried all sorts of variations, but I'm missing some magic sauce here.

Change your routes.rb to
devise_for :users, controllers: {
sessions: 'users/sessions'
}
And in your test, make sure you have
class SessionsControllerTest < ActionController::TestCase
tests Users::SessionsController
include Devise::TestHelpers
test "sign in sanity check" do
request.env["devise.mapping"] = Devise.mappings[:user]
user = users(:one)
post :create, email: user.email, password: 'password'
assert_response :success
end
end
(You can see how Devise itself does it for an example.)

Related

ruby on rails tutorial chapter 8 test error

I'm getting two different test errors in Chapter 8.2.1 of Michael Hartl's Ruby on Rails Tutorial. I'm new to Rails, but I have triple checked for syntax errors and anything else I could find. Any help is very much appreciated.
Error Message 1:
ERROR["test_should_get_new", Minitest::Result, 0.9693643249993329]
test_should_get_new#Minitest::Result (0.97s)
NameError: NameError: undefined local variable or method users_new_url' for #<UsersControllerTest:0x00000006e953f8>
test/controllers/users_controller_test.rb:5:inblock in '
Error Message 2:
ERROR["test_invalid_signup_information", Minitest::Result, 0.8977870759990765]
test_invalid_signup_information#Minitest::Result (0.90s)
ActionController::RoutingError: ActionController::RoutingError: No route matches [POST] "/signup"
test/integration/users_signup_test.rb:8:in block (2 levels) in <class:UsersSignupTest>'
test/integration/users_signup_test.rb:7:inblock in '
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'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users
end
Sessions Controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
# Log the user in and redirect to the user's show page.
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
Users Controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = "Welcome to your new profile!"
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
Users controller test
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get users_new_url
assert_response :success
end
end
Users Signup Test
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user#invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.field_with_errors'
assert_select 'form[action="/signup"]'
end
test "valid signup information" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: { name: "Example User",
email: "user#example.com",
password: "password",
password_confirmation: "password" } }
end
follow_redirect!
assert_template 'users/show'
assert_not flash.nil?
end
end
In your users_controller_test, the code doesn't know what users_new_url is. This is probably because that route doesn't exist. You will most likely have to do something like get new_user_path, but you can find out by typing rake routes and getting the list of your available routes.
Here's an example of what rake routes will output:
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
You can reference a named path by appending _path to the name. i.e. users_path will map to the "users#index"controller and method.
rake routes will also help for your second problem, which is that you do not have a route defined for POST /signup -- you have a GET /signup.
So, you'll need to add a line like:
post '/signup', to: 'users#create'
This route will map to your UsersController's #create method, which I see you have in your code.

Rspec looking for route in specific controller

After I upgraded my app from rails 4 to rails 5 and rspec-rails from 3.0 to 3.6 when running specs after upgrade I get errors:
No route matches {:action=>"/login", :controller=>"posts", :session=>{:email=>"email#example.com", :password=>"password"}}
My route is defined like this:
post 'login' => 'sessions#create'
I'm trying to access it from my helper like this:
def log_in_as(user, options = {})
post login_path , params:{session: { email: user.email,
password: "password"}}
end
In my controller spec:
RSpec.describe PostsController, type: :controller, posts: true
do
before(:each) { setup }
def setup
#user = FactoryGirl.create(:user, email: 'email#example.com')
log_in_as #user
end
#tests Code...
end
Edit:
rake routes | grep login Output:
sessions#new login GET /login(.:format)
sessions#create POST /login(.:format)

No route matches [POST] "/users"

I'm new to rails, and I'm trying to build API following Code School tutorial.
I get this error while trying to post to '/users' path.
routes file code :
Rails.application.routes.draw do
namespace :api,constraints: {subdomain: 'api'}, path: '/' do
resources :users, except: :delete
end
end
and the test code is :
require 'test_helper'
class CreatingUsersTest < ActionDispatch::IntegrationTest
test 'create users' do
post api_users_path,
{user: {name: 'test', email:'test#test.com'}}.to_json,
{'Accept' => Mime::JSON, 'Content-Type': Mime::JSON.to_s}
assert_equal response.status, 201
assert_equal response.content_type, Mime::JSON
user = json(response.body)
assert_equal api_user_url(user[:id]), response.location
end
end
And when I use rake routes :
api_users GET /users(.:format) api/users#index {:subdomain=>"api"}
POST /users(.:format) api/users#create {:subdomain=>"api"}
....
In the route you constraint the subdomain to be api
namespace :api,constraints: {subdomain: 'api'}, path: '/' do
but then in the test you call api_user_path
post api_users_path
that uses a generic hostname (test.host), and not the api hostname. The solution is to pass a specific host to the helper that satisfies the requirement.
post api_users_path(host: "api.test.host")

Rspec test to post as json

I am having problems trying to post as JSON to my controller action within my rspec test
RSpec.describe RegistrationsController, type: :controller do
context 'Adding a Valid User' do
it 'Returns Success Code and User object' do
#params = { :user => {username: 'name', school: 'school'} }.to_json
post :create, #params
end
end
end
At the moment I want to get a successful post request firing but am getting this error back all the time
Failure/Error: post :create, #params
AbstractController::ActionNotFound:
Could not find devise mapping for path "/lnf".
My routes are setup like so
Rails.application.routes.draw do
constraints(subdomain: 'api') do
devise_for :users, path: 'lnf', controllers: { registrations: "registrations" }
devise_scope :user do
post "/lnf" => 'registrations#create'
end
end
end
Rake routes outputs the following
Prefix Verb URI Pattern Controller#Action
user_registration POST /lnf(.:format) registrations#create {:subdomain=>"api"}
lnf POST /lnf(.:format) registrations#create {:subdomain=>"api"}
So i have 2 declarations for the same action?
Could anyone shed some light on this please
Thanks
Ok so after a painstaking few hours i have got my tests passing correctly and posting as json by doing the following
require 'rails_helper'
RSpec.describe RegistrationsController, type: :controller do
before :each do
request.env['devise.mapping'] = Devise.mappings[:user]
end
context 'Adding a Valid User' do
it 'Returns Success Code and User object' do
json = { user: { username: "richlewis14", school: "Baden Powell", email: "richlewis14#gmail.com", password: "Password1", password_confirmation: "Password1"}}.to_json
post :create, json
expect(response.code).to eq('201')
end
end
end
My Routes are back to normal
Rails.application.routes.draw do
constraints(subdomain: 'api') do
devise_for :users, path: 'lnf', controllers: { registrations: "registrations" }
end
end
And in my test environment I had to add
config.action_mailer.default_url_options = { host: 'localhost' }
The key here was
request.env['devise.mapping'] = Devise.mappings[:user]
Not fully sure as yet to what it does, its next on my list to find out, but my tests are starting to run and pass

Devise, Rails-API, Routing issue

I have the following routes setup inside a rails api app:
constraints subdomain: 'api', path: '/' do
namespace 'api', path: '/' do
scope module: 'v1' , constraints: ApiConstraints.new(version: 1, default: true) do
devise_scope :user do
post 'sign_in' => 'sessions#create'
delete 'sign_out' => 'sessions#destroy'
end
resources :question
end
end
end
# rake routes
Prefix Verb URI Pattern Controller#Action
api_sign_in POST /sign_in(.:format) api/v1/sessions#create {:subdomain=>"api"}
api_sign_out DELETE /sign_out(.:format) api/v1/sessions#destroy {:subdomain=>"api"}
When I got to execute this test:
require 'rails_helper'
RSpec.describe Api::V1::SessionsController, :type => :controller do
describe '#create' do
it 'creates a session' do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = User.create(email: 'rob#edukate.com', password: 'password')
post :create, action: :create, user_login: { password: user.password, email: user.email}
expect(response).to be_success
end
end
end
I get this error:
F
Failures:
1) Api::V1::SessionsController#create creates a session
Failure/Error: post :create, action: :create, user_login: { password: user.password, email: user.email}
AbstractController::ActionNotFound:
Could not find devise mapping for path "/sign_in?user_login%5Bemail%5D=rob%40edukate.com&user_login%5Bpassword%5D=password".
I have tried many variations of routes but I cannot get this simple test to pass. If I cannot get it completed like this I'll just roll my own Auth; but it appears devise is doing something odd with a Abstract controller. Thanks in advance!

Resources