Agile Web Development with Rails, Edition 5
14.5 Playtime
14.3 Iteration I3: Limiting Access
14.4 Iteration I4: Adding a Sidebar
Add admin links and a button to Logout
edit app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
</head>
<body class="<%= controller.controller_name %>">
<div id="banner">
<%= image_tag("logo.png") %>
<span class="title"><%= @page_title || "Pragmatic Bookshelf" %></span>
</div>
<div id="columns">
<div id="side">
<% if @cart %>
<%= hidden_div_if(@cart.line_items.empty?, id: 'cart') do %>
<%= render @cart %>
<% end %>
<% end %>
<%= render Order.find(session[:order_id]) if session[:order_id] -%>
<ul>
<li><a href="http://www....">Home</a></li>
<li><a href="http://www..../faq">Questions</a></li>
<li><a href="http://www..../news">News</a></li>
<li><a href="http://www..../contact">Contact</a></li>
</ul>
<% if session[:user_id] %>
<ul>
<li><%= link_to 'Orders', orders_path %></li>
<li><%= link_to 'Products', products_path %></li>
<li><%= link_to 'Users', users_path %></li>
</ul>
<%= button_to 'Logout', logout_path, method: :delete %>
<% end %>
</div>
<div id="main">
<%= yield %>
</div>
</div>
</body>
</html>
Log out
get /admin
Pragmatic Bookshelf
Welcome
It's 2016-03-07 09:44:54 -0500
We have 2 orders.
post /logout
You are being
redirected .
get http://localhost:3000/
Pragmatic Bookshelf
Logged out
Your Pragmatic Catalog
CoffeeScript
CoffeeScript is JavaScript done right. It provides all of JavaScript's
functionality wrapped in a cleaner, more succinct syntax. In the first
book on this exciting new language, CoffeeScript guru Trevor Burnham
shows you how to hold onto all the power and flexibility of JavaScript
while writing clearer, cleaner, and safer code.
$36.00
Programming Ruby 1.9 & 2.0
Ruby is the fastest growing and most exciting dynamic language
out there. If you need to get working programs delivered fast,
you should add Ruby to your toolbox.
$49.95
Rails Test Prescriptions
Rails Test Prescriptions is a comprehensive guide to testing
Rails applications, covering Test-Driven Development from both a
theoretical perspective (why to test) and from a practical perspective
(how to test effectively). It covers the core Rails testing tools and
procedures for Rails 2 and Rails 3, and introduces popular add-ons,
including Cucumber, Shoulda, Machinist, Mocha, and Rcov.
$34.95
Demonstrate that everybody can get to the store
get /
Pragmatic Bookshelf
Your Pragmatic Catalog
CoffeeScript
CoffeeScript is JavaScript done right. It provides all of JavaScript's
functionality wrapped in a cleaner, more succinct syntax. In the first
book on this exciting new language, CoffeeScript guru Trevor Burnham
shows you how to hold onto all the power and flexibility of JavaScript
while writing clearer, cleaner, and safer code.
$36.00
Programming Ruby 1.9 & 2.0
Ruby is the fastest growing and most exciting dynamic language
out there. If you need to get working programs delivered fast,
you should add Ruby to your toolbox.
$49.95
Rails Test Prescriptions
Rails Test Prescriptions is a comprehensive guide to testing
Rails applications, covering Test-Driven Development from both a
theoretical perspective (why to test) and from a practical perspective
(how to test effectively). It covers the core Rails testing tools and
procedures for Rails 2 and Rails 3, and introduces popular add-ons,
including Cucumber, Shoulda, Machinist, Mocha, and Rcov.
$34.95
Demonstrate that login is required to see the products
get /products
You are being
redirected .
get http://localhost:3000/login
Pragmatic Bookshelf
Log in
get /login
Pragmatic Bookshelf
post /login
name => dave
password => secret
You are being
redirected .
get http://localhost:3000/admin
Pragmatic Bookshelf
Welcome
It's 2016-03-07 09:44:54 -0500
We have 2 orders.
Demonstrate logged in users can see the products
get /products
Pragmatic Bookshelf
Listing products
CoffeeScript
CoffeeScript is JavaScript done right. It provides all of JavaScript...
Show
Edit
Destroy
Programming Ruby 1.9 & 2.0
Ruby is the fastest growing and most exciting dynamic language
...
Show
Edit
Destroy
Rails Test Prescriptions
Rails Test Prescriptions is a comprehensive guide to testing
...
Show
Edit
Destroy
New product
Demonstrate logged in users can see the users
get /users
Pragmatic Bookshelf
Show that the tests fail (good!)
rails test
Run options: --seed 17731
# Running:
.........................E
Error:
ProductsControllerTest#test_should_create_product:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
app/controllers/products_controller.rb:30:in `block in create'
app/controllers/products_controller.rb:29:in `create'
test/controllers/products_controller_test.rb:30:in `block (2 levels) in <class:ProductsControllerTest>'
test/controllers/products_controller_test.rb:29:in `block in <class:ProductsControllerTest>'
bin/rails test test/controllers/products_controller_test.rb:28
E
Error:
ProductsControllerTest#test_should_destroy_product:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
app/controllers/products_controller.rb:62:in `destroy'
test/controllers/products_controller_test.rb:65:in `block (2 levels) in <class:ProductsControllerTest>'
test/controllers/products_controller_test.rb:64:in `block in <class:ProductsControllerTest>'
bin/rails test test/controllers/products_controller_test.rb:63
.........E
Error:
StoreControllerTest#test_markup_needed_for_store.js.coffee_is_in_place:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
app/controllers/concerns/current_cart.rb:9:in `rescue in set_cart'
app/controllers/concerns/current_cart.rb:7:in `set_cart'
test/controllers/store_controller_test.rb:15:in `block in <class:StoreControllerTest>'
bin/rails test test/controllers/store_controller_test.rb:14
E
Error:
StoreControllerTest#test_should_get_index:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
app/controllers/concerns/current_cart.rb:9:in `rescue in set_cart'
app/controllers/concerns/current_cart.rb:7:in `set_cart'
test/controllers/store_controller_test.rb:5:in `block in <class:StoreControllerTest>'
bin/rails test test/controllers/store_controller_test.rb:4
E
Error:
UsersControllerTest#test_should_destroy_user:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
app/controllers/users_controller.rb:71:in `destroy'
test/controllers/users_controller_test.rb:55:in `block (2 levels) in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:54:in `block in <class:UsersControllerTest>'
bin/rails test test/controllers/users_controller_test.rb:53
..E
Error:
UsersControllerTest#test_should_create_user:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
app/controllers/users_controller.rb:35:in `block in create'
app/controllers/users_controller.rb:34:in `create'
test/controllers/users_controller_test.rb:22:in `block (2 levels) in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:20:in `block in <class:UsersControllerTest>'
bin/rails test test/controllers/users_controller_test.rb:19
.E
Error:
UsersControllerTest#test_should_update_user:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction
app/controllers/users_controller.rb:54:in `block in update'
app/controllers/users_controller.rb:53:in `update'
test/controllers/users_controller_test.rb:45:in `block in <class:UsersControllerTest>'
bin/rails test test/controllers/users_controller_test.rb:44
.E
Error:
DslUserStoriesTest#test_buying_a_product:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: INSERT INTO "carts" ("created_at", "updated_at") VALUES (?, ?)
app/controllers/concerns/current_cart.rb:9:in `rescue in set_cart'
app/controllers/concerns/current_cart.rb:7:in `set_cart'
test/integration/dsl_user_stories_test.rb:78:in `buys_a'
test/integration/dsl_user_stories_test.rb:43:in `block in test_buying_a_product'
test/integration/dsl_user_stories_test.rb:39:in `test_buying_a_product'
bin/rails test test/integration/dsl_user_stories_test.rb:38
E
Error:
DslUserStoriesTest#test_two_people_buying:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: INSERT INTO "carts" ("created_at", "updated_at") VALUES (?, ?)
app/controllers/concerns/current_cart.rb:9:in `rescue in set_cart'
app/controllers/concerns/current_cart.rb:7:in `set_cart'
test/integration/dsl_user_stories_test.rb:78:in `buys_a'
test/integration/dsl_user_stories_test.rb:58:in `block in test_two_people_buying'
test/integration/dsl_user_stories_test.rb:54:in `test_two_people_buying'
bin/rails test test/integration/dsl_user_stories_test.rb:53
E
Error:
UserStoriesTest#test_buying_a_product:
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: DELETE FROM "line_items"
test/integration/user_stories_test.rb:14:in `block in <class:UserStoriesTest>'
bin/rails test test/integration/user_stories_test.rb:12
.........
Finished in 54.354829s, 1.0487 runs/s, 1.8214 assertions/s.
57 runs, 99 assertions, 0 failures, 10 errors, 0 skips
edit app/models/user.rb
class User < ApplicationRecord
validates :name, presence: true, uniqueness: true
has_secure_password
after_destroy :ensure_an_admin_remains
private
def ensure_an_admin_remains
if User.count.zero?
raise "Can't delete last user"
end
end
end
edit app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
@users = User.order(:name)
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
@user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
@user = User.new(user_params)
respond_to do |format|
if @user.save
format.html { redirect_to users_url,
notice: "User #{@user.name} was successfully created." }
format.json { render :show, status: :created, location: @user }
else
format.html { render :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if @user.update(user_params)
format.html { redirect_to users_url,
notice: "User #{@user.name} was successfully updated." }
format.json { render :show, status: :ok, location: @user }
else
format.html { render :edit }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
begin
@user.destroy
flash[:notice] = "User #{@user.name} deleted"
rescue StandardError => e
flash[:notice] = e.message
end
respond_to do |format|
format.html { redirect_to users_url,
notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :password, :password_confirmation)
end
end
14.5 Playtime
14.3 Iteration I3: Limiting Access