Let's make it so an admin can see a list of all the users.
touch test/integration/admin_users_test.rb
... In class, Mike helped us setup admin_categories_test.rb
.
Since this is 'My Jams', we may not be concerned with 'categories'. Instead, we'll make it so admins see a list of all the users (so perhaps an admin can change the role of a user or delete a user).
require 'test_helper'
class AdminUsersTest < ActionDispatch::IntegrationTest
test "logged in admin sees user index" do
admin = User.create(username: "admin", password: "admin", role: 1)
ApplicationController.any_instance.stubs(:current_user).returns(admin)
visit admin_users_path
assert page.has_content?("All Users")
end
end
rails g migration AddRoleToUsers
Add role column to users table; with type :integer
and default 0, which will refer to the first element of an array containing ["default_user_role", and "admin"] ... (see next step)
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :integer, default: 0
end
end
remember to rake db:migrate
rake test
and see ...
1) Error:
AdminUsersTest#test_logged_in_admin_sees_user_index:
NoMethodError: undefined method `any_instance' for ApplicationController:Class
test/integration/admin_users_test.rb:6:in `block in <class:AdminUsersTest>'
Minitest doesn't allow us to use .stubs
by default (RSpec does).
Add to the gemfile: gem 'mocha'
(you may need to bundle install
)
Add to the test_helper.rb
: require 'mocha/mini_test'
rake test
and you should see a new error message.
1) Error:
AdminUsersTest#test_logged_in_admin_sees_user_index:
NameError: undefined local variable or method `admin_users_path' for #<AdminUsersTest:0x007fe2509c28d8>
test/integration/admin_users_test.rb:7:in `block in <class:AdminUsersTest>'
Our test is trying to visit admin_users_path
. Let's setup that route.
Add to routes.rb
...
namespace :admin do
resources :users
end
In Mike's class, resources :users
was different. In class, Mike helped us setup resources :categories
so admins could see all categories. Here we decided that an admin can see all users.
rake test
and the error should be different now.
rake test
should reveal this error...
1) Error:
AdminUsersTest#test_logged_in_admin_sees_user_index:
ActionController::RoutingError: uninitialized constant Admin
test/integration/admin_users_test.rb:7:in `block in <class:AdminUsersTest>'
mkdir app/controllers/admin
then touch app/controllers/admin/base_controller.rb
In our new base_controller.rb
...
class Admin::BaseController < ApplicationController
before_action :require_admin
def require_admin
render file: "/public/404" unless current_admin?
end
end
Here, before we render anything for the admin, we check that the current user is in fact an admin.
rake test
and the new error complains that we don't have an Admin::UsersController
1) Error:
AdminUsersTest#test_logged_in_admin_sees_user_index:
ActionController::RoutingError: uninitialized constant Admin::UsersController
test/integration/admin_users_test.rb:7:in `block in <class:AdminUsersTest>'
create one! touch app/controllers/admin/users_controller.rb
class Admin::UsersController < Admin::BaseController
def index
end
end
1) Error:
AdminUsersTest#test_logged_in_admin_sees_user_index:
NoMethodError: undefined method `current_admin?' for #<Admin::UsersController:0x007f9edf75abb8>
app/controllers/admin/base_controller.rb:5:in `require_admin'
test/integration/admin_users_test.rb:7:in `block in <class:AdminUsersTest>'
Our Admin::BaseController
is attempting to check if the current user is an admin with current_admin?
but we haven't created that method yet.
Go to application_controller.rb
and add the method ...
def current_admin?
current_user && current_user.admin?
end
so now the application_controller.rb
looks something like ...
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
helper_method :current_user
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def current_admin?
current_user && current_user.admin?
end
end
run rake test
and see a new error ...
1) Error:
AdminUsersTest#test_logged_in_admin_sees_user_index:
NoMethodError: undefined method `admin?' for #<User:0x007fb9772cc030>
app/controllers/application_controller.rb:12:in `current_admin?'
app/controllers/admin/base_controller.rb:5:in `require_admin'
test/integration/admin_users_test.rb:7:in `block in <class:AdminUsersTest>'
go to User.rb
and define the role for default users and admins. While we're at it, lets add validations for the User. (if you haven't already).
class User < ActiveRecord::Base
has_secure_password
validates :username, presence: true, uniqueness: true
enum role: %w(default admin)
end
rake test
and now we have a new error.
Our new error is
1) Error:
AdminUsersTest#test_logged_in_admin_sees_user_index:
ActionView::MissingTemplate: Missing template admin/users/index, admin/base/index, application/index with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in:
* "/Users/adam/Desktop/2/my_jams/app/views"
test/integration/admin_users_test.rb:7:in `block in <class:AdminUsersTest>'
Create the view directory
mkdir app/views/admin
mkdir app/views/admin/users
(It may not let you create both directories at once, so create the first one for /admin
then create /users
Create the view touch app/views/admin/users/index.html.erb
In the view, add some html with the text we're expecting in our test. <h1>All Users</h1>
rake test
and ...
Hooray! We're passing! We just created Authorization for our application.
git commit
that shit.
if you want to play around with the sad paths, start with ...
test "default user does not see admin users index" do
user = User.create(username: "default_user", password: "cheese", role: 0)
ApplicationController.any_instance.stubs(:current_user).returns(user)
visit admin_users_path
refute page.has_content?("All Users")
assert page.has_content?("The page you were looking for doesn't exist.")
end
Nice, Adam!