Permalink
Browse files

Make a basic user model, including secure passwords

End of chapter 6
  • Loading branch information...
1 parent 2505b42 commit 266b3282856b8629350471116c4699009a53386e @simonewebdesign committed Dec 18, 2012
View
@@ -16,6 +16,11 @@ group :development, :test do
gem 'spork', '>= 0.9.2'
end
+group :development do
+ gem 'annotate', '2.5.0'
+end
+
+
# Gems used only for assets and not required
# in production environments by default.
group :assets do
View
@@ -29,6 +29,8 @@ GEM
i18n (~> 0.6)
multi_json (~> 1.0)
addressable (2.3.2)
+ annotate (2.5.0)
+ rake
arel (3.0.2)
bcrypt-ruby (3.0.1)
bootstrap-sass (2.1.0.0)
@@ -191,6 +193,7 @@ PLATFORMS
ruby
DEPENDENCIES
+ annotate (= 2.5.0)
bcrypt-ruby (= 3.0.1)
bootstrap-sass (= 2.1)
bootstrap-will_paginate (= 0.0.6)
View
@@ -0,0 +1,24 @@
+# == Schema Information
+#
+# Table name: users
+#
+# id :integer not null, primary key
+# name :string(255)
+# email :string(255)
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+class User < ActiveRecord::Base
+ attr_accessible :name, :email, :password, :password_confirmation
+ has_secure_password
+
+ validates :name, presence: true, length: { maximum: 50 }
+ VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
+ validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
+ uniqueness: { case_sensitive: false }
+ validates :password, presence: true, length: { minimum: 6 }
+ validates :password_confirmation, presence: true
+
+ before_save { |user| user.email = email.downcase }
+end
@@ -0,0 +1,10 @@
+class CreateUsers < ActiveRecord::Migration
+ def change
+ create_table :users do |t|
+ t.string :name
+ t.string :email
+
+ t.timestamps
+ end
+ end
+end
@@ -0,0 +1,5 @@
+class AddIndexToUsersEmail < ActiveRecord::Migration
+ def change
+ add_index :users, :email, unique: true
+ end
+end
@@ -0,0 +1,5 @@
+class AddPasswordDigestToUsers < ActiveRecord::Migration
+ def change
+ add_column :users, :password_digest, :string
+ end
+end
View
@@ -11,6 +11,16 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 0) do
+ActiveRecord::Schema.define(:version => 20121218220440) 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.string "password_digest"
+ end
+
+ add_index "users", ["email"], :name => "index_users_on_email", :unique => true
end
@@ -0,0 +1,116 @@
+# == Schema Information
+#
+# Table name: users
+#
+# id :integer not null, primary key
+# name :string(255)
+# email :string(255)
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+
+require 'spec_helper'
+
+describe User do
+ before do
+ @user = User.new(name: "Example User",
+ email: "user@example.com",
+ password: "foobar",
+ password_confirmation: "foobar")
+ end
+
+ subject { @user }
+
+ it { should respond_to(:name) }
+ it { should respond_to(:email) }
+ it { should respond_to(:password_digest) }
+ # virtual attributes:
+ it { should respond_to(:password) }
+ it { should respond_to(:password_confirmation) }
+ it { should respond_to(:authenticate) }
+
+ it { should be_valid }
+
+ describe "when name is not present" do
+ before { @user.name = " " }
+ it { should_not be_valid }
+ end
+
+ describe "when email is not present" do
+ before { @user.email = " " }
+ it { should_not be_valid }
+ end
+
+ describe "when password is not present" do
+ before { @user.password = @user.password_confirmation = " " }
+ it { should_not be_valid }
+ end
+
+ describe "when password doesn't match confirmation" do
+ before { @user.password_confirmation = "mismatch" }
+ it { should_not be_valid }
+ end
+
+ describe "when password confirmation is nil" do
+ before { @user.password_confirmation = nil }
+ it { should_not be_valid }
+ end
+
+ describe "when password is too short" do
+ before { @user.password = @user.password_confirmation = "a" * 5 }
+ it { should be_invalid }
+ end
+
+ describe "when name is too long" do
+ before { @user.name = "a" * 51 }
+ it { should_not be_valid }
+ end
+
+ describe "when email format is invalid" do
+ it "should be invalid" do
+ addresses = %w[user@foo,com user_at_foo.org example.user@foo.
+ foo@bar_baz.com foo@bar+baz.com]
+ addresses.each do |invalid_address|
+ @user.email = invalid_address
+ @user.should_not be_valid
+ end
+ end
+ end
+
+ describe "when email format is valid" do
+ it "should be valid" do
+ addresses = %w[user@foo.COM A_US-ER@f.b.org frst.lst@foo.jp a+b@baz.cn]
+ addresses.each do |valid_address|
+ @user.email = valid_address
+ @user.should be_valid
+ end
+ end
+ end
+
+ describe "when email address is already taken" do
+ before do
+ user_with_same_email = @user.dup
+ user_with_same_email.email = @user.email.upcase
+ user_with_same_email.save
+ end
+
+ it { should_not be_valid }
+ end
+
+ describe "return value of authenticate method" do
+ before { @user.save }
+ let(:found_user) { User.find_by_email(@user.email) }
+
+ describe "with valid password" do
+ it { should == found_user.authenticate(@user.password) }
+ end
+
+ describe "with invalid password" do
+ let(:user_for_invalid_password) { found_user.authenticate("invalid") }
+
+ it { should_not == user_for_invalid_password }
+ specify { user_for_invalid_password.should be_false }
+ end
+ end
+
+end

0 comments on commit 266b328

Please sign in to comment.