Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Make a basic User model (including secure passwords)

  • Loading branch information...
commit fe39e915380c5a933204689cd8390cd6fa60b88d 1 parent 96572a4
Johnny Holton authored
5 Gemfile
@@ -2,12 +2,17 @@ source 'https://rubygems.org'
2 2
3 3 gem 'rails', '3.2.12'
4 4 gem 'bootstrap-sass', '2.1'
  5 +gem 'bcrypt-ruby', '3.0.1'
5 6
6 7 group :development, :test do
7 8 gem 'sqlite3', '1.3.5'
8 9 gem 'rspec-rails', '2.11.0'
9 10 end
10 11
  12 +group :development do
  13 + gem 'annotate', '2.5.0'
  14 +end
  15 +
11 16 group :assets do
12 17 gem 'sass-rails', '3.2.5'
13 18 gem 'coffee-rails', '3.2.2'
5 Gemfile.lock
@@ -28,7 +28,10 @@ GEM
28 28 activesupport (3.2.12)
29 29 i18n (~> 0.6)
30 30 multi_json (~> 1.0)
  31 + annotate (2.5.0)
  32 + rake
31 33 arel (3.0.2)
  34 + bcrypt-ruby (3.0.1)
32 35 bootstrap-sass (2.1.0.0)
33 36 builder (3.0.4)
34 37 capybara (1.1.2)
@@ -140,6 +143,8 @@ PLATFORMS
140 143 ruby
141 144
142 145 DEPENDENCIES
  146 + annotate (= 2.5.0)
  147 + bcrypt-ruby (= 3.0.1)
143 148 bootstrap-sass (= 2.1)
144 149 capybara (= 1.1.2)
145 150 coffee-rails (= 3.2.2)
29 app/models/user.rb
... ... @@ -0,0 +1,29 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: users
  4 +#
  5 +# id :integer not null, primary key
  6 +# name :string(255)
  7 +# email :string(255)
  8 +# created_at :datetime not null
  9 +# updated_at :datetime not null
  10 +#
  11 +
  12 +class User < ActiveRecord::Base
  13 + attr_accessible :email, :name, :password, :password_confirmation
  14 +
  15 + has_secure_password
  16 +
  17 + validates :name, presence: true, length: { maximum: 50 }
  18 +
  19 + VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  20 + validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
  21 + uniqueness: { case_sensitive: false }
  22 + validates :password, presence: true, length: { minimum: 6 }
  23 + validates :password_confirmation, presence: true
  24 +
  25 + before_save { |user| user.email = email.downcase }
  26 +
  27 + # scopes
  28 +
  29 +end
1  config/routes.rb
... ... @@ -1,5 +1,4 @@
1 1 SampleApp::Application.routes.draw do
2   - get "users/new"
3 2
4 3 root to: 'static_pages#home'
5 4 match '/signup', to: 'users#new'
11 db/migrate/20130226125850_create_users.rb
... ... @@ -0,0 +1,11 @@
  1 +class CreateUsers < ActiveRecord::Migration
  2 + def change
  3 + create_table :users do |t|
  4 + t.string :name
  5 + t.string :email
  6 +
  7 + t.timestamps
  8 + end
  9 + end
  10 +
  11 +end
5 db/migrate/20130226140825_add_index_to_users_email.rb
... ... @@ -0,0 +1,5 @@
  1 +class AddIndexToUsersEmail < ActiveRecord::Migration
  2 + def change
  3 + add_index :users, :email, unique: true
  4 + end
  5 +end
5 db/migrate/20130226141524_add_password_digest_to_users.rb
... ... @@ -0,0 +1,5 @@
  1 +class AddPasswordDigestToUsers < ActiveRecord::Migration
  2 + def change
  3 + add_column :users, :password_digest, :string
  4 + end
  5 +end
12 db/schema.rb
@@ -11,6 +11,16 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13
14   -ActiveRecord::Schema.define(:version => 0) do
  14 +ActiveRecord::Schema.define(:version => 20130226141524) do
  15 +
  16 + create_table "users", :force => true do |t|
  17 + t.string "name"
  18 + t.string "email"
  19 + t.datetime "created_at", :null => false
  20 + t.datetime "updated_at", :null => false
  21 + t.string "password_digest"
  22 + end
  23 +
  24 + add_index "users", ["email"], :name => "index_users_on_email", :unique => true
15 25
16 26 end
124 spec/models/user_spec.rb
... ... @@ -0,0 +1,124 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: users
  4 +#
  5 +# id :integer not null, primary key
  6 +# name :string(255)
  7 +# email :string(255)
  8 +# created_at :datetime not null
  9 +# updated_at :datetime not null
  10 +#
  11 +
  12 +require 'spec_helper'
  13 +
  14 +describe User do
  15 + before { @user = User.new(name: "Example User", email: "user@example.com",
  16 + password: "foobar", password_confirmation: "foobar") }
  17 + subject { @user }
  18 +
  19 + it { should respond_to(:name) }
  20 + it { should respond_to(:email) }
  21 + it { should respond_to(:password_digest) }
  22 + it { should respond_to(:password) }
  23 + it { should respond_to(:password_confirmation) }
  24 + it { should respond_to(:authenticate) }
  25 +
  26 +
  27 + it { should be_valid }
  28 +
  29 + describe "when name is not present" do
  30 + before { @user.name = " " }
  31 + it { should_not be_valid }
  32 + end
  33 +
  34 + describe "when email is not present" do
  35 + before { @user.email = " " }
  36 + it { should_not be_valid }
  37 + end
  38 +
  39 + describe "when name is too long" do
  40 + before { @user.name = "a" * 51 }
  41 + it { should_not be_valid }
  42 + end
  43 +
  44 + describe "when email format is invalid" do
  45 + it "should be invalid" do
  46 + addresses = %w[user@foo,com user_at_foo.org example.user@foo.
  47 + foo@bar_baz.com foo@bar+baz.com]
  48 + addresses.each do |invalid_address|
  49 + @user.email = invalid_address
  50 + @user.should_not be_valid
  51 + end
  52 +
  53 + end
  54 + end
  55 +
  56 + describe "when email format is valid" do
  57 + it "should be valid" do
  58 + addresses = %w[user@foo.COM A_US-ER@f.b.org frst.lst@foo.jp a+b@baz.cn]
  59 + addresses.each do |valid_address|
  60 + @user.email = valid_address
  61 + @user.should be_valid
  62 + end
  63 +
  64 + end
  65 + end
  66 +
  67 + describe "when email address is already taken" do
  68 + before do
  69 + user_with_same_email = @user.dup
  70 + user_with_same_email.save
  71 + end
  72 +
  73 + it { should_not be_valid }
  74 + end
  75 +
  76 + describe "when email address is already taken" do
  77 + before do
  78 + user_with_same_email = @user.dup
  79 + user_with_same_email.email = @user.email.upcase
  80 + user_with_same_email.save
  81 + end
  82 +
  83 + it { should_not be_valid }
  84 + end
  85 +
  86 + describe "when password is not present" do
  87 + before { @user.password = @user.password_confirmation = " " }
  88 + it { should_not be_valid }
  89 + end
  90 +
  91 + describe "when password doesn't match confirmation" do
  92 + before { @user.password_confirmation = "mismatch" }
  93 + it { should_not be_valid }
  94 + end
  95 +
  96 + describe "when password confirmation is nil" do
  97 + before { @user.password_confirmation = nil }
  98 + it { should_not be_valid }
  99 + end
  100 +
  101 + describe "with a password that's too short" do
  102 + before { @user.password = @user.password_confirmation = "a" * 5 }
  103 + it { should be_invalid }
  104 + end
  105 +
  106 +
  107 + describe "return value of authenticate method" do
  108 + before { @user.save }
  109 + let(:found_user) { User.find_by_email(@user.email) }
  110 +
  111 + describe "with valid password" do
  112 + it { should == found_user.authenticate(@user.password) }
  113 + end
  114 +
  115 + describe "with invalid password" do
  116 + let(:user_for_invalid_password) { found_user.authenticate("invalid") }
  117 +
  118 + it { should_not == user_for_invalid_password }
  119 + specify { user_for_invalid_password.should be_false }
  120 + end
  121 + end
  122 +
  123 +
  124 +end
9 spec/support/utilities.rb
... ... @@ -1,8 +1 @@
1   -def full_title(page_title)
2   - base_title = "Ruby on Rails Tutorial Sample App"
3   - if page_title.empty?
4   - base_title
5   - else
6   - "#{base_title} | #{page_title}"
7   - end
8   -end
  1 +include ApplicationHelper

0 comments on commit fe39e91

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