Skip to content
Browse files

Finish user edit, update, index, and destroy actions

  • Loading branch information...
1 parent 5b03ad4 commit 488aa911e4d5dc041f729a1751f0437411003842 @footmark committed Dec 6, 2011
View
8 app/assets/stylesheets/custom.css
@@ -175,4 +175,12 @@ div.field, div.actions {
#error_explanation ul li {
font-size: 12px;
list-style: square;
+}
+
+ul.users {
+ margin-top: 1em;
+}
+
+.users li {
+ list-style: none;
}
View
2 app/controllers/sessions_controller.rb
@@ -12,7 +12,7 @@ def create
render 'new'
else
sign_in user
- redirect_to user
+ redirect_back_or user
end
end
View
46 app/controllers/users_controller.rb
@@ -1,4 +1,13 @@
class UsersController < ApplicationController
+ before_filter :authenticate, :only => [:index, :edit, :update, :destroy]
+ before_filter :correct_user, :only => [:edit, :update]
+ before_filter :admin_user, :only => :destroy
+
+ def index
+ @title = "All users"
+ @users = User.paginate(:page => params[:page])
+ end
+
def show
@user = User.find(params[:id])
@title = @user.name
@@ -20,4 +29,41 @@ def create
render 'new'
end
end
+
+ def edit
+ @user = User.find(params[:id])
+ @title = "Edit user"
+ end
+
+ def update
+ @user = User.find(params[:id])
+ if @user.update_attributes(params[:user])
+ flash[:success] = "Profile updated"
+ redirect_to @user
+ else
+ @title = "Edit user"
+ render 'edit'
+ end
+ end
+
+ def destroy
+ User.find(params[:id]).destroy
+ flash[:success] = "User destroyed."
+ redirect_to users_path
+ end
+
+ private
+
+ def authenticate
+ deny_access unless signed_in?
+ end
+
+ def correct_user
+ @user = User.find(params[:id])
+ redirect_to root_path unless current_user?(@user)
+ end
+
+ def admin_user
+ redirect_to(root_path) unless current_user.admin?
+ end
end
View
22 app/helpers/sessions_helper.rb
@@ -21,6 +21,20 @@ def sign_out
self.current_user = nil
end
+ def current_user?(user)
+ user == current_user
+ end
+
+ def deny_access
+ store_location
+ redirect_to signin_path, :notice => "Please sign in to access this page."
+ end
+
+ def redirect_back_or(default)
+ redirect_to(session[:return_to] || default)
+ clear_return_to
+ end
+
private
def user_from_remember_token
@@ -30,4 +44,12 @@ def user_from_remember_token
def remember_token
cookies.signed[:remember_token] || [nil, nil]
end
+
+ def store_location
+ session[:return_to] = request.fullpath
+ end
+
+ def clear_return_to
+ session[:return_to] = nil
+ end
end
View
2 app/views/layouts/_header.html.erb
@@ -4,7 +4,9 @@
<ul>
<li><%= link_to "Home", root_path %></li>
<% if signed_in? %>
+ <li><%= link_to "Users", users_path %></li>
<li><%= link_to "Profile", current_user %></li>
+ <li><%= link_to "Setting", edit_user_path(current_user) %></li>
<% end %>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
View
6 app/views/shared/_error_messages.html.erb
@@ -1,12 +1,12 @@
-<% if @user.errors.any? %>
+<% if object.errors.any? %>
<div id="error_explanation">
<h2>
- <%= pluralize(@user.errors.count, "error") %>
+ <%= pluralize(object.errors.count, "error") %>
prohibited this user from being saved:
</h2>
<p>There were problems with the following fields:</p>
<ul>
- <% @user.errors.full_messages.each do |msg| %>
+ <% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
View
8 app/views/users/_user.html.erb
@@ -0,0 +1,8 @@
+<li>
+ <%= gravatar_for user, :size => 30 %>
+ <%= link_to user.name, user %>
+ <% if current_user.admin? %>
+ | <%= link_to "delete", :method => :delete, :confirm => "You sure?",
+ :title => "Delete #{user.name}" %>
+ <% end %>
+</li>
View
29 app/views/users/edit.html.erb
@@ -0,0 +1,29 @@
+<h1>Edit user</h1>
+
+<%= form_for @user do |f| -%>
+ <%= render 'shared/error_messages', :object => f.object %>
+ <div class="field">
+ <%= f.label :name %><br />
+ <%= f.text_field :name %>
+ </div>
+ <div class="field">
+ <%= f.label :email %><br />
+ <%= f.text_field :email %>
+ </div>
+ <div class="field">
+ <%= f.label :password %><br />
+ <%= f.password_field :password %>
+ </div>
+ <div class="field">
+ <%= f.label :password_confirmation, "Confirmation" %><br />
+ <%= f.password_field :password_confirmation %>
+ </div>
+ <div class="actions">
+ <%= f.submit "Update" %>
+ </div>
+<% end -%>
+
+<div>
+ <%= gravatar_for @user %>
+ <a href="http://gravatar.com/emails">change</a>
+</div>
View
6 app/views/users/index.html.erb
@@ -0,0 +1,6 @@
+<h1>All users</h1>
+<%= will_paginate %>
+<ul class="users">
+ <%= render @users %>
+</ul>
+<%= will_paginate %>
View
2 app/views/users/new.html.erb
@@ -1,6 +1,6 @@
<h1>Sign up</h1>
<%= form_for @user do |f| -%>
- <%= render 'shared/error_messages' %>
+ <%= render 'shared/error_messages', :object => f.object %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
View
5 db/migrate/20111206090330_add_admin_to_users.rb
@@ -0,0 +1,5 @@
+class AddAdminToUsers < ActiveRecord::Migration
+ def change
+ add_column :users, :admin, :boolean, :default => false
+ end
+end
View
3 db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20111205062031) do
+ActiveRecord::Schema.define(:version => 20111206090330) do
create_table "users", :force => true do |t|
t.string "name"
@@ -20,6 +20,7 @@
t.datetime "updated_at"
t.string "encrypted_password"
t.string "salt"
+ t.boolean "admin", :default => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
View
18 lib/tasks/sample_data.rake
@@ -0,0 +1,18 @@
+namespace :db do
+ desc "Fill database with sample data"
+ task :populate => :environment do
+ Rake::Task['db:reset'].invoke
+ admin = User.create!(:name => "Example User",
+ :email => "example@railstutorial.org",
+ :password => "foobar",
+ :password_confirmation => "foobar")
+ admin.toggle!(:admin)
+ 99.times do |n|
+ name = Faker::Name.name
+ email = "example-#{n+1}@railstutorial.org"
+ password = "password"
+ User.create!(:name => name, :email => email,
+ :password => password, :password_confirmation => password)
+ end
+ end
+end
View
198 spec/controllers/users_controller_spec.rb
@@ -3,6 +3,57 @@
describe UsersController do
render_views
+ describe "GET 'index'" do
+ describe "for non-signed-in users" do
+ it "should deny access" do
+ get :index
+ response.should redirect_to(signin_path)
+ flash[:notice].should =~ /sign in/i
+ end
+ end
+
+ describe "for signed-in users" do
+ before(:each) do
+ @user = test_sign_in(Factory(:user))
+ second = Factory(:user, :name => "Bob", :email => "another@example.com")
+ third = Factory(:user, :name => "Ben", :email => "another@example.net")
+
+ @users = [@user, second, third]
+ 30.times do
+ @users << Factory(:user, :name => Factory.next(:name),
+ :email => Factory.next(:email))
+ end
+ end
+
+ it "should be successful" do
+ get :index
+ response.should be_success
+ end
+
+ it "should have the right title" do
+ get :index
+ response.should have_selector("title", content:"All users")
+ end
+
+ it "should have an element for each user" do
+ get :index
+ @users[0..2].each do |user|
+ response.should have_selector("li", content: user.name)
+ end
+ end
+
+ it "should paginate users" do
+ get :index
+ response.should have_selector("div.pagination")
+ response.should have_selector("span.disabled", content: "Previous")
+ response.should have_selector("a", :href => "/users?page=2",
+ :content => "2")
+ response.should have_selector("a", :href => "/users?page=2",
+ :content => "Next")
+ end
+ end
+ end
+
describe "GET 'show'" do
before(:each) do
@user = Factory(:user)
@@ -98,4 +149,151 @@
end
end
end
+
+ describe "GET 'edit'" do
+ before(:each) do
+ @user = Factory(:user)
+ test_sign_in(@user)
+ end
+
+ it "should be successful" do
+ get :edit, :id => @user
+ response.should be_success
+ end
+
+ it "should have the right title" do
+ get :edit, :id => @user
+ response.should have_selector("title", content:"Edit user")
+ end
+
+ it "should have a link to change the Gravatar" do
+ get :edit, :id => @user
+ gravatar_url = "http://gravatar.com/emails"
+ response.should have_selector("a", :href => gravatar_url,
+ :content => "change")
+ end
+ end
+
+ describe "PUT 'update'" do
+ before(:each) do
+ @user = Factory(:user)
+ test_sign_in(@user)
+ end
+
+ describe "failure" do
+ before(:each) do
+ @attr = {:email => "", :name => "", :password => "",
+ :password_confirmation => ""}
+ end
+
+ it "should render the 'edit' page" do
+ put :update, :id => @user, :user => @attr
+ response.should render_template('edit')
+ end
+
+ it "should have the right title" do
+ put :update, :id => @user, :user => @attr
+ response.should have_selector("title", :content => "Edit user")
+ end
+ end
+
+ describe "success" do
+ before(:each) do
+ @attr = {:name => "New Name", :email => "user@example.org",
+ :password => "barbaz", :password_confirmation => "barbaz"}
+ end
+
+ it "should change the user's attributes" do
+ put :update, :id => @user, :user => @attr
+ @user.reload
+ @user.name.should == @attr[:name]
+ @user.email.should == @attr[:email]
+ end
+
+ it "should redirect to the user show page" do
+ put :update, :id => @user, :user => @attr
+ response.should redirect_to(user_path(@user))
+ end
+
+ it "should have a flash message" do
+ put :update, :id => @user, :user => @attr
+ flash[:success].should =~ /updated/
+ end
+ end
+ end
+
+ describe "authentication of edit/update pages" do
+ before(:each) do
+ @user = Factory(:user)
+ end
+
+ describe "for non-signed-in users" do
+ it "should deny access to 'edit'" do
+ get :edit, :id => @user
+ response.should redirect_to(signin_path)
+ end
+
+ it "should deny access to 'update'" do
+ put :update, :id => @user, :user => {}
+ response.should redirect_to(signin_path)
+ end
+ end
+
+ describe "for signed-in users" do
+ before(:each) do
+ wrong_user = Factory(:user, :email => "user@example.net")
+ test_sign_in(wrong_user)
+ end
+
+ it "should require matching users for 'edit'" do
+ get :edit, :id => @user
+ response.should redirect_to(root_path)
+ end
+
+ it "should require matching users for 'update'" do
+ put :update, :id => @user, :user => {}
+ response.should redirect_to(root_path)
+ end
+ end
+ end
+
+ describe "DELETE 'destroy'" do
+ before(:each) do
+ @user = Factory(:user)
+ end
+
+ describe "as a non-signed-in user" do
+ it "should deny access" do
+ delete :destroy, :id => @user
+ response.should redirect_to(signin_path)
+ end
+ end
+
+ describe "as a non-admin user" do
+ it "should protect the page" do
+ test_sign_in(@user)
+ delete :destroy, :id => @user
+ response.should redirect_to(root_path)
+ end
+ end
+
+ describe "as a admin user" do
+ before(:each) do
+ admin = Factory(:user, :email => "admin@example.com",
+ :admin => true)
+ test_sign_in(admin)
+ end
+
+ it "should destroy the user" do
+ lambda do
+ delete :destroy, :id => @user
+ end.should change(User, :count).by(-1)
+ end
+
+ it "should redirect to the users page" do
+ delete :destroy, :id => @user
+ response.should redirect_to(users_path)
+ end
+ end
+ end
end
View
8 spec/factories.rb
@@ -4,4 +4,12 @@
user.email "mhartl@example.com"
user.password "foobar"
user.password_confirmation "foobar"
+end
+
+Factory.sequence :name do |n|
+ "Person #{n}"
+end
+
+Factory.sequence :email do |n|
+ "person-#{n}@example.com"
end
View
19 spec/models/user_spec.rb
@@ -137,4 +137,23 @@
end
end
end
+
+ describe "admin attribute" do
+ before(:each) do
+ @user = User.create!(@attr)
+ end
+
+ it "should respond to admin" do
+ @user.should respond_to(:admin)
+ end
+
+ it "should not be an admin by default" do
+ @user.should_not be_admin
+ end
+
+ it "should be convertible to an admin" do
+ @user.toggle!(:admin)
+ @user.should be_admin
+ end
+ end
end

0 comments on commit 488aa91

Please sign in to comment.
Something went wrong with that request. Please try again.