Hi so I'm working on chapter 8.2.6 of Hartl's Rails tutorial
My application fails a test that I wrote for testing the 'sign out' link.
Here is a copy of my command prompt
C:\Sites\sample_app>bundle exec rspec spec/
.............F.................................
Failures:
1) Authentication signin with valid information followed by signout
Failure/Error: before { click_link "Sign out" }
ActionController::RoutingError:
uninitialized constant SessionController
# ./spec/requests/authenticate_pages_spec.rb:35:in `block (5 levels) in <to
p (required)>'
Finished in 1.17 seconds
47 examples, 1 failure
Failed examples:
rspec ./spec/requests/authenticate_pages_spec.rb:36 # Authentication signin with
valid information followed by signout
Here is the relevant part of the test code (spec/requests/authenticate_pages_spec.rb)
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
sign_out
redirect_to root_url
end
end
config/routes
SampleApp::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
root 'static_pages#home'
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'session#destroy', via: 'delete'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
Your indicator here is uninitialized constant SessionController.
Your controller name is plural, SessionsController
If you look at your routes.rb file, you will notice your typo.
match '/signout', to: 'session#destroy', via: 'delete'
which should look like this:
match '/signout', to: 'sessions#destroy', via: 'delete'
Related
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
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/.)
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
So I am following Michael Hartl's Rails tutorial and I am on chapter 5 (https://www.railstutorial.org/book/filling_in_the_layout).
When I run the final test that he adds for the sign up link:
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get signup_path
assert_response :success
end
end
I get this error when I run the test:
ERROR["test_should_get_new", UsersControllerTest, 2016-07-01 17:48:25 +0100]
test_should_get_new#UsersControllerTest (1467391705.83s)
ActionController::UrlGenerationError: ActionController::UrlGenerationError: No route matches {:action=>"/signup", :controller=>"users"}
test/controllers/users_controller_test.rb:6:in `block in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:6:in `block in <class:UsersControllerTest>'
Here is the routes file:
Rails.application.routes.draw do
root 'static_pages#home'
get '/signup', to: 'users#new'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
end
I have used the signup_path helper in the views as a link and they work fine.
Why is test trying to access an action called "/signup" when I have defined in the routes that "signup" should become the new action in the users controller?
Since it's a controller test (rather than feature test), your controller shouldn't care which url you visited. Therefore, get expects an action, not a path.
Change
get signup_path
to
get :new
If you want to test the route, you can modify your test case to following.
assert_generates asserts that a particular option generate a particular path.
assert_generates '/signup', {controller: 'users', action: 'new'}
assert_recognizes is the reverse of assert_generates. It asserts that a given path is recognized and routes it to a particular spot in your application.
assert_recognizes({ controller: 'users', action: 'new'}, '/signup')
The assert_routing assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of assert_generates and assert_recognizes.
assert_routing({ path: 'signup', method: :get }, { controller: 'users', action: 'new' })
I'm new to ruby on rails, and so far, I have created the user login, signup, signout, but I wanna create an admin user, and I have no idea how to do this.
route.rb is:
Rails.application.routes.draw do
get 'courses/index'
get 'courses/new'
get 'courses/edit'
get 'courses/show'
get 'course/index'
get 'course/new'
get 'course/edit'
get 'course/show'
get 'sessions/signin'
get 'sessions/main'
get 'sessions/profile'
get 'sessions/setting'
get 'users/new'
get 'home/index'
resources :users, path_names: {new: "signup"} do
collection do
get "main", action: :new
end
end
resources :sessions, path_names: {new: "signin", destroy: "signout"} do
collection do
get :signin
get :main
get :profile
get :setting
end
end
resources :home, only: [], path: "" do
get :about
end
root 'home#index'
resources :courses, only: [:index, :new, :edit, :show]
#resources :course, only: [:index, :new, :edit, :show]
resources :courses
resources :course_groups
patch 'course_groups/:id/add_course', to: 'course_groups#add_course', as: 'course_group_add_course'
delete 'course_groups/:id/delete_course', to: 'course_groups#destory_course', as: 'course_group_destory_course'
resources :rules
patch 'rules/:id/add_group', to: 'rules#add_group', as: 'rule_add_course_group'
delete 'rules/:id/delete_group', to: 'rules#destroy_group', as: 'rule_destroy_course_group'
resources :requirements
patch 'requirements/:id/add_rule', to: 'requirements#add_rule', as: 'requirement_add_rules'
delete 'requirements/:id/delete_rule', to: 'requirements#destroy_rule', as: 'requirement_destroy_rules'
#resources :plans
resources :users do
resources :plans
end
patch 'users/:user_id/plans/:id/add_course', to: 'plans#add_course', as: 'plan_add_course'
delete 'users/:user_id/plans/:id/delete_course', to: 'plans#destory_course', as: 'plan_destory_course'
match '/about', to: 'home#about', via: 'get'
match '/signup', to: 'users#new', via: 'get'
match ':controller(/:action(/:id))(.:format)', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
match '/main', to: 'users#new', via: 'get'
#match '/profile', to: 'sessions#profile', via: 'get'
match '/setting', to: 'sessions#setting', via: 'get'
match '/editname', to: 'users#edit', via: 'get'
match '/show', to: 'users#show', via: 'get'
match '/profile', to: 'users#profile', via: 'get'
#match '/info', to: 'users#info', via: 'get'
#match '/changepass', to: 'users#edit', via: 'get'
end
and my users_controller.rb is:
class UsersController < ApplicationController
before_filter :check_if_signned_in, only: [:show, :edit, :update, :delete]
before_filter :signed_in_user, only: [:edit, :update]
before_filter :skip_password_attribute, only: :update
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user, notice: 'User was sucessfully created!'
else
render action: "new"
end
end
#if current user exits, then it can get back to the main page of user
def show
if current_user.nil?
#user = User.find(params[:id])
else
#user = User.find(current_user)
end
end
def edit
##user = User.find(params[:id])
##user = User.find(current_user)
#user = current_user
#user.save
#title = "Edit profile"
end
def update
#user = User.find(params[:id])
##user = User.find(current_user)
#if #user.update_attributes(user_params)
if #user.update_attributes(user_params)
flash[:success] = "Profile updated."
#sign_in #user_params
redirect_to #user
else
#title = "Edit profile"
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def signed_in_user
redirect_to signin_path, notice: "Please sign in." unless signed_in?
end
def edit_user
params.require(:user).permit(:name)
end
def skip_password_attribute
if params[:password].blank? && params[:password_confirmation].blank?
params.except!(:password, :password_confirmation)
end
end
end
the application_controller.rb is:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
#protect_from_forgery with: :exception
protect_from_forgery
#before_filter :session_expire
#before_filter :update_active_time
include SessionsHelper
def check_if_signned_in
deny_access unless signed_in?
end
#def update_active_time
# session[:expires_at] = default_expire
#end
def is_owner
current_user.id == params[:id]
end
#private
# def get_session_time_left
# expire_time = session[:expires_at] #|| default_expire
# a = expire_time
# b = Time.now
# #session_time_left = (a - b).do_i
##session_time_left = (expire_time - Time.now).do_i
# end
end
Anyone can teach me how to create an admin user please? When the admin user logins, it will go to another different page.
Thank you in advance!
Without being rude, your code really needs to be cleaned up.
Your routes alone are a mess - I think I remember giving you some code to help them the other day, and it appears you've used it! However, you've left the other routes in there still - which is likely going to cause big issues down the line
Routes
Firstly, you need to get your routes in order:
#config/routes.rb
resources :courses
resources :users, path_names: {new: "signup"} do
collection do
get "main", action: :new
end
end
resources :sessions, path_names: {new: "signin", destroy: "signout", index: "main", edit: "profile", update: "setting"}
resources :home, only: [], path: "" do
get :about
end
root 'home#index'
resources :courses, only: [:index, :new, :edit, :show]
resources :course_groups do
patch :add_course
delete :delete_course
end
resources :rules do
patch :add_group
delete :delete_group
end
resources :requirements do
patch :add_rule
delete :delete_rule
end
resources :users do
resources :plans do
patch :add_course
delete :delete_course
end
end
match '/about', to: 'home#about', via: 'get'
match '/signup', to: 'users#new', via: 'get'
match ':controller(/:action(/:id))(.:format)', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
match '/main', to: 'users#new', via: 'get'
match '/setting', to: 'sessions#setting', via: 'get'
match '/editname', to: 'users#edit', via: 'get'
Simply, everything in Rails is resource / object - orientated. This includes the routes, and you should therefore make sure that every route you have is constructed around a resource (that's why you can define routes as resources etc)
--
Admin
To create an admin user, there are several options available to you:
Have a separate admin model
Create an admin attribute in your User model
I would strongly recommend including an admin attribute in your User model - make it a boolean column like this:
#new migration
add_column :users, :admin, :boolean
This will allow you to call the following
#user = User.find params[:id]
#user.admin? #-> true / false
This will allow you to use several conditional statements in both the controllers & views of your application, to determine if the user had admin privileges or not
When I run RSpec I am getting 4 errors all stating:
undefined local variable or method `signin_path' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x4203fa8>
But I am running other tests that use this helper and path with no problem, it is only in the relationship controller tests that do not work with it.
relationship_controller_spec.rb
require 'spec_helper'
describe RelationshipsController do
let(:user) { FactoryGirl.create(:user) }
let(:other_user) { FactoryGirl.create(:user) }
before { sign_in user }
describe "creating a relationship with Ajax" do
it "should increment the Relationship count" do
expect do
xhr :post, :create, relationship: { followed_id: other_user.id }
end.to change(Relationship, :count).by(1)
end
it "should respond with success" do
xhr :post, :create, relationship: { followed_id: other_user.id }
response.should be_success
end
end
describe "destroying a relationship with Ajax" do
before { user.follow!(other_user) }
let(:relationship) { user.relationships.find_by_followed_id(other_user) }
it "should decrement the Relationship count" do
expect do
xhr :delete, :destroy, id: relationship.id
end.to change(Relationship, :count).by(-1)
end
it "should respond with success" do
xhr :delete, :destroy, id: relationship.id
response.should be_success
end
end
end
Utilities.rb:
def sign_in(user)
visit signin_path
fill_in 'Email', with: user.email.upcase
fill_in 'Password', with: user.password
click_button 'Sign In'
cookies[:remember_token] = user.remember_token
end
routes.rb:
resources :users do
member do
get :following, :followers
end
end
resources :sessions, only: [:create, :destroy, :new]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
# Application Root
root to: 'static_pages#home'
# Static Pages
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
# Users
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
Controller specs cannot interact with pages in the same way that feature specs do, so your sign_in utility will not work for them.
If your controller specs rely on a signed-in user, you will need to stub your current_user method. If you use Devise, here's a helpful page from their wiki: https://github.com/plataformatec/devise/wiki/How-To:-Stub-authentication-in-controller-specs
Going through Hartl's Rails tutorial and on Chapter 5.4.2 I am not able to get a certain test to pass.
Here is the error:
1) UserPages GET /user_pages works! (now write some real specs)
Failure/Error: get user_pages_index_path
NameError:
undefined local variable or method `user_pages_index_path' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x007f9106e2cce8>
# ./spec/requests/user_pages_spec.rb:7:in `block (3 levels) in <top (required)>'
Here is the test in user_pages_spec.rb:
require 'spec_helper'
describe "UserPages" do
describe "GET /user_pages" do
it "works! (now write some real specs)" do
# Run the generator again with the
# --webrat flag if you want to use webrat methods/matchers
get user_pages_index_path
response.status.should be(200)
end
end
end
Here is the routes file:
get "users/new"
root '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'
match 'static_pages/home', to: 'static_pages#home', via: 'get'
Any input is appreciated
Sorry about the formatting. In the very beginning of that section is a spec file: spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before { visit signup_path }
it { should have_content('Sign up') }
it { should have_title(full_title('Sign up')) }
end
end
and I am getting the following error:
Failure/Error: get user_pages_index_path
NameError: undefined local variable or method `user_pages_index_path' for #
Here is the rake routes output:
Prefix Verb URI Pattern Controller#Action
users_new GET /users/new(.:format) users#new
root GET / static_pages#home
signup GET /signup(.:format) users#new
help GET /help(.:format) static_pages#help
about GET /about(.:format) static_pages#about
contact GET /contact(.:format) static_pages#contact
static_pages_home GET /static_pages/home(.:format) static_pages#home
Just remove the contents at "user_pages_spec.rb"
cause there is no such method called user_pages_index_path
so, here is what it should be
user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before { visit signup_path }
it { should have_content('Sign up') }
it { should have_title(full_title('Sign up')) }
end
end
Also, At /config/routes.rb file
SampleApp::Application.routes.draw do
get "users/new"
root '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
I was having same issue and I just commented out the "user_pages_spec.rb" file. When I did that I passed all the tests. Is this the correct answer, I don't know but as I stated it allows for the tests to pass.