Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Finish user edit, update, index, and destroy actions page 423

  • Loading branch information...
commit fb515c6fbcbf3f98663f84038cb5395b7ca0b9ee 1 parent 5963b7a
@wdk122 authored
View
15 app/assets/stylesheets/custom.css.scss
@@ -171,6 +171,21 @@ input {
@extend .error;
}
+/* users index */
+
+.users {
+ list-style: none;
+ margin: 0;
+ li {
+ overflow: auto;
+ padding: 10px 0;
+ border-top: 1px solid $grayLighter;
+ &:last-child {
+ border-bottom: 1px solid $grayLighter;
+ }
+ }
+}
+
View
2  app/controllers/sessions_controller.rb
@@ -7,7 +7,7 @@ def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
- redirect_to user
+ redirect_back_or user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
View
47 app/controllers/users_controller.rb
@@ -1,5 +1,9 @@
class UsersController < ApplicationController
+ before_filter :signed_in_user, only: [:index, :edit, :update, :destroy]
+ before_filter :correct_user, only: [:edit, :update]
+ before_filter :admin_user, only: :destroy
+
def show
@user = User.find(params[:id])
end
@@ -18,4 +22,45 @@ def create
render 'new'
end
end
-end
+
+ def edit
+ end
+
+ def update
+ if @user.update_attributes(params[:user])
+ flash[:success] = "Profile updated"
+ sign_in @user
+ redirect_to @user
+ else
+ render 'edit'
+ end
+ end
+
+ def index
+ @users = User.paginate(page: params[:page])
+ end
+
+ def destroy
+ User.find(params[:id]).destroy
+ flash[:success] = "User destroyed."
+ redirect_to users_url
+ end
+
+ private
+
+ def signed_in_user
+ unless signed_in?
+ store_location
+ redirect_to signin_url, notice: "Please sign in."
+ end
+ 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
13 app/helpers/sessions_helper.rb
@@ -17,8 +17,21 @@ def current_user
@current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
+ def current_user?(user)
+ user == current_user
+ end
+
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
+
+ def redirect_back_or(default)
+ redirect_to(session[:return_to] || default)
+ session.delete(:return_to)
+ end
+
+ def store_location
+ session[:return_to] = request.fullpath
+ end
end
View
4 app/views/layouts/_header.html.erb
@@ -7,14 +7,14 @@
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
- <li><%= link_to "Users", '#' %></li>
+ <li><%= link_to "Users", users_path %></li>
<li id="fat-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Account
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
- <li><%= link_to "Settings", '#' %></li>
+ <li><%= link_to "Settings", edit_user_path(current_user) %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
View
7 app/views/users/_user.html.erb
@@ -0,0 +1,7 @@
+<li>
+ <%= gravatar_for user, size: 52 %>
+ <%= link_to user.name, user %>
+ <% if current_user.admin? && !current_user?(user) %>
+ | <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
+ <% end %>
+</li>
View
27 app/views/users/edit.html.erb
@@ -0,0 +1,27 @@
+<% provide(:title, "Edit user") %>
+<h1>Update your profile</h1>
+
+<div class="row">
+ <div class="span6 offset3">
+ <%= form_for(@user) do |f| %>
+ <%= render 'shared/error_messages' %>
+
+ <%= f.label :name %>
+ <%= f.text_field :name %>
+
+ <%= f.label :email %>
+ <%= f.text_field :email %>
+
+ <%= f.label :password %>
+ <%= f.password_field :password %>
+
+ <%= f.label :password_confirmation, "Confirm Password" %>
+ <%= f.password_field :password_confirmation %>
+
+ <%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
+ <% end %>
+
+ <%= gravatar_for @user %>
+ <a href="http://gravatar.com/emails">change</a>
+ </div>
+</div>
View
10 app/views/users/index.html.erb
@@ -0,0 +1,10 @@
+<% provide(:title, 'All users') %>
+<h1>All users</h1>
+
+<%= will_paginate %>
+
+<ul class="users">
+ <%= render @users %>
+</ul>
+
+<%= will_paginate %>
View
5 db/migrate/20130203071345_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
7 db/schema.rb
@@ -11,15 +11,16 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20130201215804) do
+ActiveRecord::Schema.define(:version => 20130203071345) do
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
t.string "password_digest"
t.string "remember_token"
+ t.boolean "admin", :default => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
View
20 lib/tasks/sample_data.rake
@@ -0,0 +1,20 @@
+namespace :db do
+ desc "Fill database with sample data"
+ task populate: :environment do
+ 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
8 spec/factories.rb
@@ -1,8 +1,12 @@
FactoryGirl.define do
factory :user do
- name "Michael Hartl"
- email "michael@example.com"
+ sequence(:name) { |n| "Person #{n}" }
+ sequence(:email) { |n| "person_#{n}@example.com" }
password "foobar"
password_confirmation "foobar"
+
+ factory :admin do
+ admin true
+ end
end
end
View
8 spec/models/user_spec.rb
@@ -26,9 +26,17 @@
it { should respond_to(:password) }
it { should respond_to(:password_confirmation) }
it { should respond_to(:remember_token) }
+ it { should respond_to(:admin) }
it { should respond_to(:authenticate) }
it { should be_valid }
+ it { should_not be_admin }
+
+ describe "with admin attribute set to 'true'" do
+ before { @user.toggle!(:admin) }
+
+ it { should be_admin }
+ end
describe "when name is not present" do
before { @user.name = " " }
View
99 spec/requests/authentication_pages_spec.rb
@@ -28,15 +28,15 @@
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
- before do
- fill_in "Email", with: user.email
- fill_in "Password", with: user.password
- click_button "Sign in"
- end
+ before { sign_in user }
it { should have_selector('title', text: user.name) }
+
+ it { should have_link('Users', href: users_path) }
it { should have_link('Profile', href: user_path(user)) }
+ it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
+
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
@@ -45,4 +45,91 @@
end
end
end
-end
+
+ describe "authorization" do
+
+ describe "for non-signed-in users" do
+ let(:user) { FactoryGirl.create(:user) }
+
+ describe "when attempting to visit a protected page" do
+ before do
+ visit edit_user_path(user)
+ fill_in "Email", with: user.email
+ fill_in "Password", with: user.password
+ click_button "Sign in"
+ end
+
+ describe "after signing in" do
+
+ it "should render the desired protected page" do
+ page.should have_selector('title', text: 'Edit user')
+ end
+ end
+ end
+
+ describe "in the users controller" do
+
+ describe "visiting the edit page" do
+ before { visit edit_user_path(user) }
+ it { should have_selector('title', text: 'Sign in') }
+ end
+
+ describe "submitting to the update action" do
+ before { put user_path(user) }
+ specify { response.should redirect_to(signin_path) }
+ end
+
+ describe "visiting the user index" do
+ before { visit users_path }
+ it { should have_selector('title', text: 'Sign in') }
+ end
+ end
+ end
+
+ describe "as wrong user" do
+ let(:user) { FactoryGirl.create(:user) }
+ let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
+ before { sign_in user }
+
+ describe "visiting Users#edit page" do
+ before { visit edit_user_path(wrong_user) }
+ it { should_not have_selector('title', text: full_title('Edit user')) }
+ end
+
+ describe "submitting a PUT request to the Users#update action" do
+ before { put user_path(wrong_user) }
+ specify { response.should redirect_to(root_path) }
+ end
+ end
+
+ describe "as non-admin user" do
+ let(:user) { FactoryGirl.create(:user) }
+ let(:non_admin) { FactoryGirl.create(:user) }
+
+ before { sign_in non_admin }
+
+ describe "submitting a DELETE request to the Users#destroy action" do
+ before { delete user_path(user) }
+ specify { response.should redirect_to(root_path) }
+ end
+ end
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
View
84 spec/requests/user_pages_spec.rb
@@ -4,6 +4,52 @@
subject { page }
+ describe "index" do
+
+ let(:user) { FactoryGirl.create(:user) }
+
+ before do
+ sign_in user
+ visit users_path
+ end
+
+ it { should have_selector('title', text: 'All users') }
+ it { should have_selector('h1', text: 'All users') }
+
+ describe "pagination" do
+
+ before(:all) { 30.times { FactoryGirl.create(:user) } }
+ after(:all) { User.delete_all }
+
+ it { should have_selector('div.pagination') }
+
+ it "should list each user" do
+ User.paginate(page: 1).each do |user|
+ page.should have_selector('li', text: user.name)
+ end
+ end
+ end
+
+ describe "delete links" do
+
+ it { should_not have_link('delete') }
+
+ describe "as an admin user" do
+ let(:admin) { FactoryGirl.create(:admin) }
+ before do
+ sign_in admin
+ visit users_path
+ end
+
+ it { should have_link('delete', href: user_path(User.first)) }
+ it " should be able to delete another user" do
+ expect { click_link('delete') }.to change(User, :count).by(-1)
+ end
+ it { should_not have_link('delete', href: user_path(admin)) }
+ end
+ end
+ end
+
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
@@ -59,4 +105,42 @@
end
end
end
+
+ describe "edit" do
+ let(:user) { FactoryGirl.create(:user) }
+ before do
+ sign_in user
+ visit edit_user_path(user)
+ end
+
+ describe "page" do
+ it { should have_selector('h1', text: 'Update your profile') }
+ it { should have_selector('title', text: 'Edit user') }
+ it { should have_link('change', href: 'http://gravatar.com/emails') }
+ end
+
+ describe "with invalid information" do
+ before { click_button "Save changes" }
+
+ it { should have_content('error') }
+ end
+
+ describe "with valid information" do
+ let(:new_name) { "New Name" }
+ let(:new_email) { "new@example.com" }
+ before do
+ fill_in "Name", with: new_name
+ fill_in "Email", with: new_email
+ fill_in "Password", with: user.password
+ fill_in "Confirm Password", with: user.password
+ click_button "Save changes"
+ end
+
+ it { should have_selector('title', text: new_name) }
+ it { should have_selector('div.alert.alert-success') }
+ it { should have_link('Sign out', href: signout_path) }
+ specify { user.reload.name.should == new_name }
+ specify { user.reload.email.should== new_email }
+ end
+ end
end
View
11 spec/support/utilities.rb
@@ -1 +1,10 @@
-include ApplicationHelper
+include ApplicationHelper
+
+def sign_in(user)
+ visit signin_path
+ fill_in "Email", with: user.email
+ fill_in "Password", with: user.password
+ click_button "Sign in"
+ # Sign in when not using Capybara as well.
+ cookies[:remember_token] = user.remember_token
+end
Please sign in to comment.
Something went wrong with that request. Please try again.