Permalink
Browse files

Make a basic User model (including secure passwords)

  • Loading branch information...
1 parent 1b9f208 commit 6853c55a7d3cf560a45a224b2c1565194fc91e0b @scanales committed May 16, 2012
View
2 Gemfile
@@ -2,11 +2,13 @@ source 'https://rubygems.org'
gem 'rails', '3.2.3'
gem 'bootstrap-sass', '2.0.0'
+gem 'bcrypt-ruby', '3.0.1'
group :development, :test do
gem 'sqlite3', '1.3.5'
gem 'rspec-rails', '2.9.0'
gem 'guard-rspec', '0.5.5'
+ gem 'annotate', '~> 2.4.1.beta'
end
# Gems used only for assets and not required
View
4 Gemfile.lock
@@ -29,7 +29,9 @@ GEM
i18n (~> 0.6)
multi_json (~> 1.0)
addressable (2.2.7)
+ annotate (2.4.1.beta1)
arel (3.0.2)
+ bcrypt-ruby (3.0.1)
bootstrap-sass (2.0.0)
builder (3.0.0)
capybara (1.1.2)
@@ -150,6 +152,8 @@ PLATFORMS
ruby
DEPENDENCIES
+ annotate (~> 2.4.1.beta)
+ bcrypt-ruby (= 3.0.1)
bootstrap-sass (= 2.0.0)
capybara (= 1.1.2)
coffee-rails (= 3.2.2)
View
26 app/models/user.rb
@@ -0,0 +1,26 @@
+# == 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
+ has_secure_password
+
+ before_save { self.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
View
10 db/migrate/20120501220303_create_users.rb
@@ -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
View
5 db/migrate/20120511175521_add_index_to_users_email.rb
@@ -0,0 +1,5 @@
+class AddIndexToUsersEmail < ActiveRecord::Migration
+ def change
+ add_index :users, :email, unique: true
+ end
+end
View
5 db/migrate/20120513214120_add_password_digest_to_users.rb
@@ -0,0 +1,5 @@
+class AddPasswordDigestToUsers < ActiveRecord::Migration
+ def change
+ add_column :users, :password_digest, :string
+ end
+end
View
26 db/schema.rb
@@ -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 => 20120513214120) 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
View
118 spec/models/user_spec.rb
@@ -0,0 +1,118 @@
+# == 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 { @user = User.new(name: "Example User", email: "user@example.com", password: "foobar", password_confirmation: "foobar") }
+ 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 "email address with mixed case" do
+ let(:mixed_case_email) { "Foo@ExAMPle.CoM" }
+
+ it "should be saved as all lower-case" do
+ @user.email = mixed_case_email
+ @user.save
+ @user.reload.email.should == mixed_case_email.downcase
+ end
+ end
+
+ describe "with password 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
+
+ describe "when password is not present" do
+ before { @user.password = @user.password_confirmation = " " }
+ it { should_not be_valid }
+ end
+
+ describe "when password and confirmation dont match" 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 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 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.]
+ 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_USER@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
+end

0 comments on commit 6853c55

Please sign in to comment.