Permalink
Browse files

Add user controller

  • Loading branch information...
1 parent 28a6f55 commit 42e73292bbc8589c528c2f40814773c1c88db774 Bartosz Pranczke committed Aug 4, 2011
View
1 .gitignore
@@ -7,3 +7,4 @@ db/*.sqlite3
*.un~
Session.vim
+vendor/ruby
View
13 Gemfile
@@ -11,7 +11,6 @@ gem 'sqlite3'
gem 'sass-rails', "~> 3.1.0.rc"
gem 'coffee-script'
gem 'uglifier'
-
gem 'jquery-rails'
gem 'therubyracer'
# Use unicorn as the web server
@@ -22,13 +21,15 @@ gem 'therubyracer'
# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'
-group :test, :development do
- gem "rspec-rails"
-end
group :test do
# Pretty printed test output
gem 'turn', :require => false
- gem 'webrat'
- gem 'factory_girl_rails'
+end
+gem "rspec-rails", :group => [:test, :development]
+group :test do
+ gem "factory_girl_rails"
+ gem 'capybara', git: 'git://github.com/jnicklas/capybara.git'
+ gem "launchy"
+ gem 'database_cleaner'
end
View
44 Gemfile.lock
@@ -1,3 +1,15 @@
+GIT
+ remote: git://github.com/jnicklas/capybara.git
+ revision: e9efc8042bd1f9e414df3bca5eb834367ce0f46c
+ specs:
+ capybara (1.0.0)
+ mime-types (>= 1.16)
+ nokogiri (>= 1.3.3)
+ rack (>= 1.0.0)
+ rack-test (>= 0.5.4)
+ selenium-webdriver (~> 2.0)
+ xpath (~> 0.1.4)
+
GEM
remote: http://rubygems.org/
specs:
@@ -30,27 +42,35 @@ GEM
activesupport (= 3.1.0.rc5)
activesupport (3.1.0.rc5)
multi_json (~> 1.0)
+ addressable (2.2.6)
ansi (1.3.0)
arel (2.1.4)
bcrypt-ruby (2.1.4)
builder (3.0.0)
+ childprocess (0.2.0)
+ ffi (~> 1.0.6)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.1.1)
+ database_cleaner (0.6.7)
diff-lcs (1.1.2)
erubis (2.7.0)
- execjs (1.2.0)
+ execjs (1.2.4)
multi_json (~> 1.0)
- factory_girl (2.0.1)
+ factory_girl (2.0.2)
factory_girl_rails (1.1.0)
factory_girl (~> 2.0.0)
railties (>= 3.0.0)
+ ffi (1.0.9)
hike (1.2.0)
i18n (0.6.0)
jquery-rails (1.0.12)
railties (~> 3.0)
thor (~> 0.14)
+ json_pure (1.5.3)
+ launchy (2.0.5)
+ addressable (~> 2.2.6)
libv8 (3.3.10.2)
mail (2.3.0)
i18n (>= 0.4.0)
@@ -85,7 +105,7 @@ GEM
rdoc (~> 3.4)
thor (~> 0.14.6)
rake (0.9.2)
- rdoc (3.8)
+ rdoc (3.9.1)
rspec (2.6.0)
rspec-core (~> 2.6.0)
rspec-expectations (~> 2.6.0)
@@ -99,12 +119,18 @@ GEM
activesupport (~> 3.0)
railties (~> 3.0)
rspec (~> 2.6.0)
- sass (3.1.5)
+ rubyzip (0.9.4)
+ sass (3.1.6)
sass-rails (3.1.0.rc.5)
actionpack (~> 3.1.0.rc1)
railties (~> 3.1.0.rc1)
sass (>= 3.1.4)
sprockets (>= 2.0.0.beta.9)
+ selenium-webdriver (2.3.2)
+ childprocess (>= 0.1.9)
+ ffi (>= 1.0.7)
+ json_pure
+ rubyzip
sprockets (2.0.0.beta.12)
hike (~> 1.2)
rack (~> 1.0)
@@ -123,23 +149,23 @@ GEM
uglifier (1.0.0)
execjs (>= 0.3.0)
multi_json (>= 1.0.2)
- webrat (0.7.3)
- nokogiri (>= 1.2.0)
- rack (>= 1.0)
- rack-test (>= 0.5.3)
+ xpath (0.1.4)
+ nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
+ capybara!
coffee-script
+ database_cleaner
factory_girl_rails
jquery-rails
+ launchy
rails (= 3.1.0.rc5)
rspec-rails
sass-rails (~> 3.1.0.rc)
sqlite3
therubyracer
turn
uglifier
- webrat
View
2 app/assets/javascripts/users.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
View
3 app/assets/stylesheets/users.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Users controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
View
33 app/controllers/users_controller.rb
@@ -0,0 +1,33 @@
+class UsersController < ApplicationController
+ def new
+ @user = User.new
+ end
+
+ def create
+ @user = User.new(params[:user])
+ if @user.save
+ flash[:success] = "Your account has been created. Welcome to Wordscloud!"
+ redirect_to @user
+ else
+ render "new"
+ end
+ end
+
+ def show
+ @user = User.find(params[:id])
+ end
+
+ def edit
+ @user = User.find(params[:id])
+ end
+
+ def update
+ @user = User.find(params[:id])
+ if @user.update_attributes(params[:user])
+ flash[:success] = "Profile updated"
+ redirect_to @user
+ else
+ render "edit"
+ end
+ end
+end
View
2 app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
View
20 app/models/user.rb
@@ -0,0 +1,20 @@
+class User < ActiveRecord::Base
+ has_secure_password
+
+ attr_accessible :username, :fullname, :email, :password
+ before_create { generate_token(:auth_token) }
+
+ validates :username, presence: true, length: { maximum: 20 },
+ uniqueness: { case_sensitive: false }
+ validates :fullname, presence: true, length: { maximum: 30 }
+ email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
+ validates :email, format: { with: email_regex },
+ uniqueness: { case_sensitive: false }, length: { maximum: 30 }
+ validates :password, length: { in: 5..25 }
+
+ def generate_token(column)
+ begin
+ self[column] = SecureRandom.urlsafe_base64
+ end while User.exists?(column => self[column])
+ end
+end
View
5 app/views/layouts/_footer.html.erb
@@ -0,0 +1,5 @@
+<% if Rails.env.development? %>
+<div class="debug" style="border: 1px solid red; margin: 150px; background-color: #F3703A;">
+ <%= debug(params) %>
+</div>
+<% end %>
View
24 app/views/layouts/application.html.erb
@@ -1,14 +1,16 @@
<!DOCTYPE html>
<html>
-<head>
- <title>Wordscloud</title>
- <%= stylesheet_link_tag "application" %>
- <%= javascript_include_tag "application" %>
- <%= csrf_meta_tags %>
-</head>
-<body>
-
-<%= yield %>
-
-</body>
+ <head>
+ <title>Wordscloud</title>
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "application" %>
+ <%= csrf_meta_tags %>
+ </head>
+ <body>
+ <% flash.each do |name, msg| %>
+ <%= content_tag :div, msg, :id => "flash_#{name}" %>
+ <% end %>
+ <%= yield %>
+ <%= render 'layouts/footer' %>
+ </body>
</html>
View
32 app/views/users/_user_form.html.erb
@@ -0,0 +1,32 @@
+<%= form_for @user do |f| %>
+ <% if f.object.errors.any? %>
+ <div id="error_explanation">
+ <ul>
+ <% f.object.errors.full_messages.delete_if { |msg| msg =~ /digest/ }.each do
+ |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+<div class="field">
+ <%= f.label :fullname %>
+ <%= f.text_field :fullname %>
+</div>
+<div class="field">
+ <%= f.label :email %>
+ <%= f.text_field :email %>
+</div>
+<div class="field">
+ <%= f.label :password %>
+ <%= f.password_field :password %>
+</div>
+<div class="field">
+ <%= f.label :username %>
+ <%= f.text_field :username %>
+</div>
+<div class="action">
+ <% caption = (controller.action_name =~ /new|create/ ) ? "Create my account": "Save changes" %>
+ <%= f.submit caption %>
+</div>
+<% end %>
View
1 app/views/users/edit.html.erb
@@ -0,0 +1 @@
+<%= render 'user_form' %>
View
1 app/views/users/new.html.erb
@@ -0,0 +1 @@
+<%= render 'user_form' %>
View
1 app/views/users/show.html.erb
@@ -0,0 +1 @@
+<%= "#{@user.username} - username" %>
View
2 config/environments/test.rb
@@ -5,7 +5,7 @@
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
- config.cache_classes = true
+ config.cache_classes = false
# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
View
2 config/routes.rb
@@ -1,4 +1,6 @@
Wordscloud::Application.routes.draw do
+ resources :users
+ match '/signup', to: 'users#new'
# The priority is based upon order of creation:
# first created -> highest priority.
View
12 db/migrate/20110803201437_create_users.rb
@@ -0,0 +1,12 @@
+class CreateUsers < ActiveRecord::Migration
+ def change
+ create_table :users do |t|
+ t.string :username
+ t.string :fullname
+ t.string :email
+ t.string :password_digest
+
+ t.timestamps
+ end
+ end
+end
View
5 db/migrate/20110803205749_add_auth_token_to_users.rb
@@ -0,0 +1,5 @@
+class AddAuthTokenToUsers < ActiveRecord::Migration
+ def change
+ add_column :users, :auth_token, :string
+ end
+end
View
25 db/schema.rb
@@ -0,0 +1,25 @@
+# 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 => 20110803205749) do
+
+ create_table "users", :force => true do |t|
+ t.string "username"
+ t.string "fullname"
+ t.string "email"
+ t.string "password_digest"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "auth_token"
+ end
+
+end
View
6 spec/factories.rb
@@ -0,0 +1,6 @@
+Factory.define :user do |f|
+ f.sequence(:username) { |n| "john#{n}" }
+ f.fullname 'Doe'
+ f.sequence(:email) { |n| "test#{n}@example.com" }
+ f.password 'foobar'
+end
View
103 spec/models/user_spec.rb
@@ -0,0 +1,103 @@
+require 'spec_helper'
+
+describe User do
+ before(:each) do
+ @attr = { username: "johnkowalski", fullname: "John Kowalski",
+ email: "john@example.net", password: "foobar" }
+ end
+
+ describe "Create a user" do
+
+ it "should create a new instance given valid attributes" do
+ User.create!(@attr)
+ end
+
+ it "should require a name" do
+ invalid_user = User.new(@attr.merge(username: ""))
+ invalid_user.should_not be_valid
+ end
+
+ it "should require a fullname" do
+ invalid_user = User.new(@attr.merge(fullname: ""))
+ invalid_user.should_not be_valid
+ end
+
+ it "should require an email" do
+ invalid_user = User.new(@attr.merge(email: ""))
+ invalid_user.should_not be_valid
+ end
+
+ it "should require a password" do
+ invalid_user = User.new(@attr.merge(password: ""))
+ invalid_user.should_not be_valid
+ end
+
+ it "should accept valid email addresses" do
+ addresses = %w[user@foo.com THE_USER@foo.bar.org first.name@foo.jp]
+ addresses.each do |address|
+ valid_email_user = User.new(@attr.merge(email: address))
+ valid_email_user.should be_valid
+ end
+ end
+
+ it "should reject invalid email addresses" do
+ addresses = %w[user@foo,com users_at_foo.org example.user@foo.]
+ addresses.each do |address|
+ invalid_email_user = User.new(@attr.merge(email: address))
+ invalid_email_user.should_not be_valid
+ end
+ end
+
+ it "should reject email addresses identical up to case" do
+ upcased_email = @attr[:email].upcase
+ User.create!(@attr.merge(email: upcased_email, username: "paul"))
+ user_with_duplicate_email = User.new(@attr)
+ user_with_duplicate_email.should_not be_valid
+ end
+
+ it "should reject username identical up to case" do
+ User.create!(@attr.merge(username: @attr[:username].upcase, email: "paul@foo.net"))
+ user_with_duplicate_username = User.new(@attr)
+ user_with_duplicate_username.should_not be_valid
+ end
+
+ it "should reject duplicate usernames" do
+ User.create!(@attr)
+ user_with_duplicate_username = User.new(@attr.merge(email: "paul@example.net"))
+ user_with_duplicate_username.should_not be_valid
+ end
+
+ it "should reject duplicate email addresses" do
+ User.create!(@attr)
+ user_with_duplicate_email = User.new(@attr.merge(username: "paulkowalski"))
+ user_with_duplicate_email.should_not be_valid
+ end
+
+ it "should reject password shorter than 5 chars" do
+ user_with_short_password = User.new(@attr.merge(password: "aa"))
+ user_with_short_password.should_not be_valid
+ end
+
+ it "should reject password longer than 25 chars" do
+ user_with_long_password = User.new(@attr.merge(password: "a"*26))
+ user_with_long_password.should_not be_valid
+ end
+
+ it "should reject username longer than 20 chars" do
+ user_with_long_username = User.new(@attr.merge(username: "a"*21))
+ user_with_long_username.should_not be_valid
+ end
+
+ it "should reject fullname longer than 30 chars" do
+ user_with_long_fullname = User.new(@attr.merge(fullname: "a"*31))
+ user_with_long_fullname.should_not be_valid
+ end
+
+ it "should have 2 different auth_token for users with the same password" do
+ first_user = User.create!(@attr)
+ second_user = User.create!(@attr.merge(username: "second", email: "second@o.com"))
+ first_user.auth_token.should_not == second_user.auth_token
+ end
+ end
+end
+
View
40 spec/requests/users_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe "Users" do
+ describe "get /signup" do
+ it "should not create account with invalid parameters" do
+ lambda do
+ visit signup_path
+ fill_in "Fullname", with: ""
+ fill_in "Email", with: ""
+ fill_in "Password", with: ""
+ fill_in "Username", with: ""
+ click_button "Create my account"
+ page.should have_css("div#error_explanation")
+ end.should_not change(User, :count)
+ end
+
+ it "should create account with valid parameters" do
+ lambda do
+ visit signup_path
+ fill_in "Fullname", with: "Foo Bar"
+ fill_in "Email", with: "foo@example.com"
+ fill_in "Password", with: "foobar"
+ fill_in "Username", with: "foo"
+ click_button "Create my account"
+ page.should have_content("Your account has been created")
+ end.should change(User, :count).by(1)
+ end
+
+ it "should edit user's account with valid parameters" do
+ user = Factory(:user)
+ visit edit_user_path(user)
+ fill_in "Username", with: "new_username"
+ fill_in "Password", with: "foobar"
+ click_button "Save changes"
+ page.should have_content("updated")
+ page.should have_content("new_username")
+ current_path.should eq(user_path(user))
+ end
+ end
+end
View
16 spec/spec_helper.rb
@@ -2,7 +2,7 @@
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
-
+require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
@@ -18,10 +18,20 @@
config.mock_with :rspec
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
- config.use_transactional_fixtures = true
+ config.use_transactional_fixtures = false
+ config.before(:suite) do
+ DatabaseCleaner.strategy = :truncation
+ end
+
+ config.before(:each) do
+ DatabaseCleaner.start
+ end
+
+ config.after(:each) do
+ DatabaseCleaner.clean
+ end
end

0 comments on commit 42e7329

Please sign in to comment.