Skip to content

Commit

Permalink
Make a basic User model (including secure passwords)
Browse files Browse the repository at this point in the history
  • Loading branch information
chancipher committed Apr 27, 2013
1 parent 2d0faaa commit edae082
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ source 'https://rubygems.org'

gem 'rails', '3.2.13'
gem 'bootstrap-sass','2.0.4'
gem 'bcrypt-ruby', '3.0.1'

# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
Expand All @@ -14,6 +15,10 @@ group :development,:test do
gem 'spork','0.9.2'
end

group :development do
gem 'annotate','2.5.0'
end

gem 'json'

# Gems used only for assets and not required
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ GEM
activesupport (3.2.13)
i18n (= 0.6.1)
multi_json (~> 1.0)
annotate (2.5.0)
rake
arel (3.0.2)
bcrypt-ruby (3.0.1)
bootstrap-sass (2.0.4.0)
builder (3.0.4)
capybara (1.1.2)
Expand Down Expand Up @@ -170,6 +173,8 @@ PLATFORMS
ruby

DEPENDENCIES
annotate (= 2.5.0)
bcrypt-ruby (= 3.0.1)
bootstrap-sass (= 2.0.4)
capybara (= 1.1.2)
coffee-rails (= 3.2.2)
Expand Down
24 changes: 24 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -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 :email, :name, :password, :password_confirmation
# attr_accessor :password, :password_confirmation
has_secure_password

before_save { |user| user.email = email.downcase }

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
end
10 changes: 10 additions & 0 deletions db/migrate/20130427030334_create_users.rb
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions db/migrate/20130427042216_add_index_to_users_email.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
add_index :users, :email, unique: true
end
end
5 changes: 5 additions & 0 deletions db/migrate/20130427043403_add_password_digest_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddPasswordDigestToUsers < ActiveRecord::Migration
def change
add_column :users, :password_digest, :string
end
end
26 changes: 26 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.

ActiveRecord::Schema.define(:version => 20130427043403) 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
116 changes: 116 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
@@ -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: "chan.cipher@gmail.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)}
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 name is too long" do
before { @user.name = "a" * 51 }
it { should_not be_valid }
end

describe "when name is too long" do
before { @user.name = "a" * 51 }
it { should_not be_valid }
end

describe "when email is not present" do
before { @user.email = " " }
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 "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 "with a password that's too short" do
before { @user.password = @user.password_confirmation = "a" * 5 }
it { should be_invalid }
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 edae082

Please sign in to comment.