14.3 Iteration I3: Limiting Access 14.1 Iteration I1: Adding Users
Generate empty controllers for sessions and administration
rails generate controller Sessions new create destroy
create app/controllers/sessions_controller.rb
route get "sessions/destroy"
route get "sessions/create"
route get "sessions/new"
invoke erb
create app/views/sessions
create app/views/sessions/new.html.erb
create app/views/sessions/create.html.erb
create app/views/sessions/destroy.html.erb
invoke test_unit
create test/functional/sessions_controller_test.rb
invoke helper
create app/helpers/sessions_helper.rb
invoke test_unit
create test/unit/helpers/sessions_helper_test.rb
rails generate controller Admin index
create app/controllers/admin_controller.rb
route get "admin/index"
invoke erb
create app/views/admin
create app/views/admin/index.html.erb
invoke test_unit
create test/functional/admin_controller_test.rb
invoke helper
create app/helpers/admin_helper.rb
invoke test_unit
create test/unit/helpers/admin_helper_test.rb
Implement login in and out by storing the user_id in the session
edit app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.authenticate(params[:name], params[:password])
if user
session[:user_id] = user.id
redirect_to admin_url
else
redirect_to login_url, alert: "Invalid user/password combination"
end
end
def destroy
session[:user_id] = nil
redirect_to store_url, notice: "Logged out"
end
end
Create the view using form_for as there is no underlying model
edit app/views/sessions/new.html.erb
<div class="depot_form">
<% if flash[:alert] %>
<p id="notice"><%= flash[:alert] %></p>
<% end %>
<%= form_tag do %>
<fieldset>
<legend>Please Log In</legend>
<div>
<%= label_tag :name, 'Name:' %>
<%= text_field_tag :name, params[:name] %>
</div>
<div>
<%= label_tag :password, 'Password:' %>
<%= password_field_tag :password, params[:password] %>
</div>
<div>
<%= submit_tag "Login" %>
</div>
</fieldset>
<% end %>
</div>
Create a landing page for the administrator
edit app/views/admin/index.html.erb
<h1>Welcome</h1>
It's <%= Time.now %>
We have <%= pluralize(@total_orders, "order") %>.
Make the orders count available to the admin page
edit app/controllers/admin_controller.rb
class AdminController < ApplicationController
def index
@total_orders = Order.count
end
end
Connect the routes to the controller actions
edit config/routes.rb
Depot::Application.routes.draw do
get 'admin' => 'admin#index'
controller :sessions do
get 'login' => :new
post 'login' => :create
delete 'logout' => :destroy
end
resources :users
resources :orders
resources :line_items
resources :carts
get "store/index"
resources :products do
get :who_bought, on: :member
end
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
root to: "store#index", as: 'store'
# ...
end
Do a login
get /login
post /login
get http://localhost:3000/admin
Fix the sessions controller test
edit test/functional/sessions_controller_test.rb
require 'test_helper'
class SessionsControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
test "should login" do
dave = users(:one)
post :create, name: dave.name, password: 'secret'
assert_redirected_to admin_url
assert_equal dave.id, session[:user_id]
end
test "should fail login" do
dave = users(:one)
post :create, name: dave.name, password: 'wrong'
assert_redirected_to login_url
end
test "should logout" do
delete :destroy
assert_redirected_to store_url
end
end
rake test
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
..........
Finished in 0.330774 seconds.
10 tests, 31 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 27050
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
...............................................
Finished in 0.969226 seconds.
47 tests, 79 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 14247
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
Loaded suite /home/rubys/.rvm/gems/ruby-1.9.2-p320/gems/rake-10.1.1/lib/rake/rake_test_loader
Started
...
Finished in 0.726932 seconds.
3 tests, 47 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 16736
14.3 Iteration I3: Limiting Access 14.1 Iteration I1: Adding Users