Eric Ries: Stop Wasting People’s Time

At SLLConf this year, we decided to try an experiment of live blogging via typewith.me. The event is being simulcast to a global audience, just like last year. This is the first of a series.

Eric Ries kicked it off with an update on the Lean Startup “movement.”

Eric Ries says he’s just a figurehead, later Eric Ries referred to himself a “professional talking head”. He isn’t lean startup, we are.
We are experiencing a worldwide entrepreneurial renaissance.

Everyone turn your cell phones on! Being off the internet is irresponsible and direspectful to our ancestors who created this technology for us.

Lean Startup is global — it is no longer a Silicon Valley phenomenon. Check out Lean Startup Meetups.

We are in the process of democratizing entrepreneurship.
But, it has also been institutionalized…

  • Harvard Business School- MVP Product Fund
  • Stanford University- Lean Launchpad
  • BYU- Lean Startup Research Project

Books

  • the Entrepreneur’s Guide to Customer Development
  • Steve Blank’s Four Steps to the Epiphany
  • (and there was another one that we missed)

Entrepreneurship is not just two guys in a garage, it is a discipline

GhostBusters is one of the great entrepreneurship movies of all time
All great entrepreneurs have great stories. The movies play out like this:
Act 1) Characters& timing
Act 2) Boring stuff — the “photo montage” of people at the keyboard drinking beer
Act 3) How to divide up the spoils
This conference is about Act 2 — how does it really happen.

“A startup is a human institution designed to deliver a new product or service under conditions of extreme uncertainty.” — Eric’s definition

startup = experiment

“our future GDP growth depends on the quality and caliber of our collective imagination”

We are building companies that have fundamentally no customers and are pulled off the shelves

Frederick Winslow Taylor (March 20, 1856 – March 21, 1915) was an American mechanical engineer who sought to improve industrial efficiency.

Scientific Management:
* Study work to find the best way
* Management by exception
* Standardize work into tasks
* Compensate workers based on performance

What are we doing now that will later be revealed as myth and prejudice?

The Pivot
“better to be misunderstood than ignored”
Runway- number of pivots you still have the opportunity to make
Speed Wins

Validated learning reduces the time between pivots
Acheiving Failures = successfully exeuting on a bad plan
Why is it important to do things efficiently if we’re doing the wrong thing?

W. Edwards Deming and Taiichi Ohno- start of the Lean Revolution

Who is the customer? whose eyes matter in determining value vs. waste?

Minimize the total time through the loop
Ideas -> Build -> Code -> Measure -> Data -> Learn
see image here: http://lean.st/principles/build-measure-learn

Ship it anyways and see what happens? Why spend time agruing about the details if there the chance that no one will want it.

How do we figure out what we need to learn as quickly as possible

The Toyota Way
Foundation is long term thinking -> culture that supports people to do their best work

He displayed this pyramid:

  • People
  • Culture
  • Process
  • Acountability

“We have begun to learn how to keep innovators accountable”
Use learning milestones instead of product milestones
What are the inputs to our business plan right now
better have bad news that is true than good news that we made up
“If the 10% customer adoption does not happen, everything in this business plan is irrelevant” should be a big red banner!” via @timolehes
Tune the engine -> every business has different math

Pivot or persevere? when experiments reach diminishing returns, it’s time to pivot.

“If we alllow ourselves to fail, we can train our judgement to get better over time”

Hosted Continuous Integration with CloudBees

We’ve keeping an eye out for hosted continuous integration for some time. Recently, I heard about CloudBees from John Dunham at Sauce Labs (another great cloud-hosted service which will run your Selenium tests). It seems some ofthe Hudson folk have escaped from Oracle, renamed/forked the open source project as “Jenkins” and are setting up shop with $4M from Matrix Partners with the goal of offering a platform for hosting Java apps, including the Java-based continuous integration system, Jenkins (nee Hudson).

I’ve tried it out on one Rails project I’ve tried, I’ve got specs running, but not passing and I’m not sure why yet. Here’s what I’ve figured out so far…

[ruby]
export rvm_path=~/.rvm
echo ‘export rvm_path=~/.rvm’ > ~/.rvmrc
mkdir -p ~/.rvm/src
cd ~/.rvm/src
rm -rf ./rvm/
git clone -depth 1 git://github.com/wayneeseguin/rvm.git
cd rvm
./install
rvm reload
rvm reset
cd $WORKSPACE
rvm install ree-1.8.7
rvm use ree-1.8.7
rvm gem install bundler -no-rdoc -no-ri
rvm exec bundle install
cp config/database.yml.dev config/database.yml
rvm exec rake db:create:all
rvm exec rake db:migrate
rvm exec rake spec
[/ruby]

Multi-Browser Testing w/ Capybara

On March 23rd, Blazing Cloud and Engine Yard hosted 25 Ruby enthusiasts for a Capybara and RSpec Multi-Browser testing workshop. This 2-hour session walked students through building a new Rails 3 app using RSpec and Capybara paired with Selenium for automated browser testing. A custom IDE developed by Engine Yard was used to minimize setup time and allow students to jump right into development. Blazing Cloud is excited to offer more mini-workshops in the future. Feel free to email [email protected] with any suggestions about which topics you’d like to see covered.

Download a video of the workshop (unzip, then open default.html) here

Amazon SES in 20 minutes

1) Sign into AWS account

2) Get your Account Security key, and secret key

3) add to bundle : gem ‘aws-ses’, :require => ‘aws/ses’

4) you are going to need to know that you are sandboxed - this means you can only send to - and send from emails that you verify.

here is a quick bit of code that you can drop in your rails ./script dir to verify emails and test the basics of the gem

- Begin file -

#!/usr/bin/env ruby
require File.expand_path('../../config/boot',  __FILE__)
require 'aws/ses'
class SesTool
  attr_reader :ses
  def initialize
    @ses = AWS::SES::Base.new(
      :access_key_id => 'KEY_HERE',
      :secret_access_key => 'SECRET_HERE')
  end
  def addresses_act(name,email)
    self.ses.addresses.send(name,email) unless email.blank?
  end
  def send_to(email,message)
    self.ses.send_email( :to => [email],
                        :source    => addresses_list.first,
                        :subject   => 'Subject Line',
                        :text_body => %%
  Stuff from ses_email\n
    #{message.inspect}
    %)
  end
  def addresses_list
    self.ses.addresses.list.result
  end
  def run(opts)
    opts = opts.dup
    case opts.shift
    when 'send' then
      puts 'send'
      send_to(opts.shift,opts)
    when 'list' then
      puts 'list'
      p addresses_list
    when 'verify' then
      addresses_act('verify',opts.shift)
    when 'delete' then
      addresses_act('delete',opts.shift)
    else
      puts 'nope'
    end
  end
end
SesTool.new.run(ARGV)

- End File -
Examples

ruby ses_email verify my_email@my_host.com
ruby ses_email verify my_email_2@my_host.com
# check your email and click the verify for both
ruby ses_email send my_email_2@my_host.com this is a message !
# done

‘rt’ - Replace Text in Ruby for Rails 3 Upgrade, Charlie Brown

https://github.com/robotarmy/rt

In the process of reworking a Rails 2.3.4 application into a Rails 3.0.5 application there were quite a few common changes. Most of the actual work happened in the spec testing layer where RSpec was moving from 1.3 to 2.5 and Webrat was being exchanged in favour of Capybara.

While my apprentice Anita Kuno and myself, Curtis Schofield, were working on this project, I mentioned it was recommended to me by Sarah Allen to take note of process and look at what can be automated. I’ve practiced this myself to an extent - one of the barriers I have encountered in this practice is being told that what you are doing is not necessary by people who are not career programmers. This kind of sentiment can take the wind out of ones sails.

What keeps the wind in sails is turning them to face the correct direction - I have to say that one of these directions (other than working for Captain Recruiter (it is a plug - have no doubt), and working beside Blazing Cloud and Sarah Allen’s Team) is to have an apprentice who is generally intelligent, enthusiastic and willing to explore.

It was Anita’s observation that we were doing many repetitive tasks - she asked if there was a way to automate that process. I responded by saying I had written something similar years back. I didn’t have the code anymore. However, I knew that we would be able to get some small practical tool going.

This tool is ‘rt’. A small test-driven program for asking an operator if they would like to run a regular expression on a line.

‘rt’ assumes that you are comfortable in writing (or copying) lines of YAML and are familiar with how to compose regular expressions. Regular expressions can be difficult to master or grasp the fundamentals of - many people will tell you that if you attempt to solve a problem with regular expressions - you will have 2 problems. In fact - they can be very useful and advantageous - as long as you do not expect them to be a complete substitute for a formal parser. I have used regular expressions for 10 years and they can be excellent when used in the correct place.

You will notice when running ‘rt’ that each of your regular expressions are executed on the every line in the file - matches are presented to you and you will be given a choice to accept the transformation or deny it (the ‘return/enter’ key will deny the change).

If you would like to use the actual file that we used to transform the code from RSpec 1 to 2, Webrat to Capybara and a few things around Rails 2 to rails 3. You can find this file in the repository

You will also see that we renamed an entire object ‘user’ to ‘person’ and all the plural elements of such.

Remember Tron, Users are People.

  • here is an example of taking out debugger statements
    ? !ruby/regexp /^\s+debugger\n$/m
    : ""
  • here is an example of converting - with a set of steps ‘users to people’ and ‘user to person’
    # user to person helpers
    ? !ruby/regexp /user/
    : person
    ? !ruby/regexp /User/
    : Person
    ? !ruby/regexp /users/
    : people
    ? !ruby/regexp /persons/
    : people
    ? !ruby/regexp /peoples/
    : people
  • Webrat existed in a couple different incarnations - depending on the implementer - in this one I use references to match expressions
    ? !ruby/regexp /current_dom\.css\((.+?)\)\.text\.include\?\((.+?)\)\.should be_true/
    : "page.should have_css(\1, :text => \2)"
    ? !ruby/regexp /current_dom\.at\((.+?)\)\.text\.include\?\((.+?)\)\.should == true/
    : "page.should have_css(\1, :text => \2)"
    

so how does one run ‘rt’?

‘rt’ can take a file or a directory - it looks for a .snoopy file at startup

This .snoopy file is you YAML collection of regular expression key value pairs

example .snoopy

---
# capybara migration helpers
? !ruby/regexp /request\.path/
: current_path
? !ruby/regexp /field_named/
: find_field

Any questions? email : [email protected]

:wq 

More about Typus Authentication

In Device the easiest way to support an admin role is to simply add an attribute that can be used to identify administrators, which doesn’t involve any migration. So after following Lorien’s post, I set @admin_user to a Device user model and made sure it had all the required Typus attributes.
Below are the steps I followed:

1) Add admin attribute
[sourcecode language="ruby"]
$rails generate migration add_admin_to_user admin:boolean
[/sourcecode]

[sourcecode language="ruby"]
class AddAdminRoleToUsers < ActiveRecord::Migration
def self.up
add_column :users, :admin, :boolean, :default => false
end

def self.down
remove_column :users, :admin
end
end

[/sourcecode]

2) Add required Typus attributes.

[sourcecode language="ruby"]
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
……
#typus authentication. Need this attributes to simulate typus’s admin_user
def locale
::I18n.locale
end

def application(name)
Typus.application(name)
end

def can?(*args)
true
end

def cannot?(*args)
!can?(*args)
end

def applications
Typus.applications
end
end
[/sourcecode]

3) Set @admin_user
[sourcecode language="ruby"]
module Typus
module Authentication
module Devise
protected
include Base
def authenticate

#call devise auth
authenticate_user!
end

# Set the admin user.
def admin_user
@admin_user = current_user if current_user && current_user.admin?
end
end
end
end

[/sourcecode]

You could also use table inheritance, which is a software pattern described by Martin Fowler. The basic idea is that another field in the base database table is used to store the type of the object. But you will have to twist it around to make it work.

*Note
We have implemented this way before Francesc Esplugas’s devise support to typus.

Typus Custom Authentication

We really like Typus at Blazing Cloud, and we end up using it in most of our Ruby on Rails projects. It provides good enough UI for a lot of our data entry needs, and is very quick to set-up. We also use Devise for authentication, and frequently end up with both in the same project. In many cases it is ideal for Typus to have it’s own auth system, as often the end users of the system are not also administrators of the system. However, there are some cases where the end users are also users of the Typus interface, and in that case it is convenient to have only one set of credentials to log in to both parts of the system.

We found a fairly simple way to plug a custom auth component into Typus which I will demonstrate here using Devise authentication as an example. To provide a custom mechanism for authentication all you need to do is include a module inside a module called Authentication inside a module called Typus, and then set the config.authentication property in the Typus initializer equal to the symbol version of your module’s name. For example, here is our custom module which we called Devise:

[ruby]
module Typus
module Authentication
module Devise

protected

include Base

def authenticate

#when typus auth is turned on it tries to reference @admin_user, so we need to set it to something
#FakeUser is used in typus internally, so that’s what we’re using
@admin_user = FakeUser.new

#call devise auth
authenticate_user!
end

end
end
end
[/ruby]

The key here is to include the authenticate method, which gets called by Typus when auth is turned on. Then in the Typus initializer you need to configure Typus to use your module:

[ruby]
config.authentication = :devise
[/ruby]

This just refers to the Devise module by the symbol version of its name. Now just require your module in your project, and that’s it! Now when you visit your Typus admin page you will be required to log in using Devise authentication.

Note the line in the Devise module that creates the @admin_user property:

[ruby]
#when typus auth is turned on it tries to reference @admin_user, so we need to set it to something
#FakeUser is used in typus internally, so that’s what we’re using
@admin_user = FakeUser.new
[/ruby]

The @admin_user variable must be set to a valid user if authentication is turned on in Typus or you will get errors. The FakeUser user is used internally by Typus as a placeholder model, and has all of the required attributes so we use it here. The Typus user model is only used if you have authentication turned on, and isn’t required for any of the basic functionality. However, you can also set @admin_user to a real user model such as your Devise user model, if you make sure it has the required Typus attributes. For example, if you want turn on user specific localization in Typus you can set @admin_user to a user model that has the “locale” property set on it.

Ruby on Rails class webinar

We’ve decided to offer our popular Ruby on Rails class to remote participants. I’ll be giving a repeat of the first class today (Sunday, Jan 30th) at 4pm PST and classes will be recorded. The class lasts for 2 hours. The regular class time will be Tuesdays 6:30-8:30pm PST and there will be 8 class sessions with homework.

The first class is free. We’ll be looking at survey responses and decide on pricing based on a final assessment of the remote experience.

This class is an introduction to Rails and also covers the Ruby language. It is aimed at programmers who are new to Ruby and Rails. I am co-teaching the class with Curtis Shofield. We’ll be using the test first teaching approach which provides a firm foundation in best practices using the RSpec testing framework.

Class Topics
1/25 Introduction to Rails
2/1 Ruby and RSpec
2/8 ActiveRecord
2/15 Power Ruby
2/22 Controllers
3/1 REST and Integration Testing
3/8 Associations
3/15 TBD

If you want to participate, join the google group for more information, look at recent postings for setup details and I will post the URL for the meeting website before the class today.

Devise Authentication in Rails 3

Devise Github project page: https://github.com/plataformatec/devise

After some google searching I arrived at the decision to use Devise over Authlogic for my brand spanking new rails 3 app. I haven’t really had that much experience with authlogic in the past, besides using it in my previous rails 3 app. It was a little tricky to get it working with rails 3 and I wasn’t the biggest fan of the documentation (I felt it could have been a little more granular). That being said I have never used Devise but the yammering on the internet suggests it is a cleaner solution and works out of the box with rails 3. (http://stackoverflow.com/questions/4136121/rails-3-authentication-authlogic-vs-devise) I also liked some of the out of the box features it came with:

  • Database Authenticatable: encrypts and stores a password in the database to validate the authenticity of an user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
  • Token Authenticatable: signs in a user based on an authentication token (also known as “single access token”). The token can be given both through query string or HTTP Basic Authentication.
  • Confirmable: sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
  • Recoverable: resets the user password and sends reset instructions.
  • Registerable: handles signing up users through a registration process, also allowing them to edit and destroy their account.
  • Rememberable: manages generating and clearing a token for remembering the user from a saved cookie.
  • Trackable: tracks sign in count, timestamps and IP address.
  • Timeoutable: expires sessions that have no activity in a specified period of time.
  • Validatable: provides validations of email and password. It’s optional and can be customized, so you’re able to define your own validations.
  • Lockable: locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
  • Encryptable: adds support of other authentication mechanisms besides the built-in Bcrypt (the default).

The Exploration

First things first, add “devise” to your rails Gemfile in the root directory of your application.
Note: this example assumes knowledge of the bundler gem

bundle install

Running bundle install will set you up with:

Installing bcrypt-ruby (2.1.3) with native extensions
Installing warden (1.0.3)
Installing devise (1.1.5)

Following the install docs on the Devise project page..

rails generate devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================
Some setup you must do manually if you haven't yet:
  1. Setup default url options for your specific environment. Here is an
     example of development environment:
       config.action_mailer.default_url_options = { :host => 'localhost:3000' }
     This is a required Rails configuration. In production it must be the
     actual host of your application
  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:
       root :to => "home#index"
  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:
       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>
===============================================================================

Alright, based on the install output it looks like we need to do a little setup work… However, I will leave that to the reader since they may be using a pre-existing rails application…

After you are finished configuring the application its time to create your user model.

rails generate devise User
      invoke  active_record
      create    app/models/user.rb
      invoke    test_unit
      create      test/unit/user_test.rb
      create      test/fixtures/users.yml
      create    db/migrate/20110108192129_devise_create_users.rb
      inject    app/models/user.rb
       route  devise_for :users

Great, lets take a look at what the generator created starting with the migration.

class DeviseCreateUsers < ActiveRecord::Migration   def self.up     create_table(:users) do |t|       t.database_authenticatable :null => false
      t.recoverable
      t.rememberable
      t.trackable
      # t.confirmable
      # t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
      # t.token_authenticatable
      t.timestamps
    end
    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    # add_index :users, :confirmation_token,   :unique => true
    # add_index :users, :unlock_token,         :unique => true
  end
  def self.down
    drop_table :users
  end
end

It looks like Devise gives you password encryption/storing, password recovery, session tokens, and login attempts by default. For my application I will also uncomment the lines for t.confirmable, t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both and t.token_authenticatable since I find these registration options useful out of the box and will save me time from writing those components later (not to say I still wont…).

The only thing I needed to investigate of these options was the lockable option since I wanted to understand the lock and unlock strategies.

:unlock_strategy - The strategy used for unlock. Can be :time, :email, :both (default), :none.
If :email or :both, creates a unlock_token field.
:lock_strategy - The strategy used for locking. Can be :failed_attempts (default) or :none.

Alright, now that we understand what they mean here is what my final migration looks like:

class DeviseCreateUsers < ActiveRecord::Migration   def self.up     create_table(:users) do |t|       t.database_authenticatable :null => false
      t.recoverable
      t.rememberable
      t.trackable
      t.confirmable
      t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
      t.token_authenticatable
      t.timestamps
    end
    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    add_index :users, :confirmation_token,   :unique => true
    add_index :users, :unlock_token,         :unique => true
  end
  def self.down
    drop_table :users
  end
end

Now let’s take a look at our User model.

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable, :lockable and :timeoutable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
end

It looks like based on our migration options that we will also have to uncomment token_authenticatable, :confirmable, :lockable and :timeoutable and add it to the devise option.

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :token_authenticatable, :confirmable, :lockable, :timeoutable
  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
end

We don’t need to setup our routes for user because devise has already added devise_for :users to our config/routes.rb for us. If we then run rake routes from the command line we get:

      new_user_session GET    /users/sign_in(.:format)          {:action=>"new", :controller=>"devise/sessions"}
          user_session POST   /users/sign_in(.:format)          {:action=>"create", :controller=>"devise/sessions"}
  destroy_user_session GET    /users/sign_out(.:format)         {:action=>"destroy", :controller=>"devise/sessions"}
         user_password POST   /users/password(.:format)         {:action=>"create", :controller=>"devise/passwords"}
     new_user_password GET    /users/password/new(.:format)     {:action=>"new", :controller=>"devise/passwords"}
    edit_user_password GET    /users/password/edit(.:format)    {:action=>"edit", :controller=>"devise/passwords"}
         user_password PUT    /users/password(.:format)         {:action=>"update", :controller=>"devise/passwords"}
     user_registration POST   /users(.:format)                  {:action=>"create", :controller=>"devise/registrations"}
 new_user_registration GET    /users/sign_up(.:format)          {:action=>"new", :controller=>"devise/registrations"}
edit_user_registration GET    /users/edit(.:format)             {:action=>"edit", :controller=>"devise/registrations"}
     user_registration PUT    /users(.:format)                  {:action=>"update", :controller=>"devise/registrations"}
     user_registration DELETE /users(.:format)                  {:action=>"destroy", :controller=>"devise/registrations"}
     user_confirmation POST   /users/confirmation(.:format)     {:action=>"create", :controller=>"devise/confirmations"}
 new_user_confirmation GET    /users/confirmation/new(.:format) {:action=>"new", :controller=>"devise/confirmations"}
     user_confirmation GET    /users/confirmation(.:format)     {:action=>"show", :controller=>"devise/confirmations"}
           user_unlock POST   /users/unlock(.:format)           {:action=>"create", :controller=>"devise/unlocks"}
       new_user_unlock GET    /users/unlock/new(.:format)       {:action=>"new", :controller=>"devise/unlocks"}
           user_unlock GET    /users/unlock(.:format)           {:action=>"show", :controller=>"devise/unlocks"}
                  root        /(.:format)                       {:controller=>"home", :action=>"index"}

Finally it’s time to migrate our database and create our user model.

rake db:migrate
==  DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
NOTICE:  CREATE TABLE will create implicit sequence "users_id_seq" for serial column "users.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" for table "users"
   -> 0.0553s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0020s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0021s
-- add_index(:users, :confirmation_token, {:unique=>true})
   -> 0.0115s
-- add_index(:users, :unlock_token, {:unique=>true})
   -> 0.0028s
==  DeviseCreateUsers: migrated (0.0740s) =====================================

Now it’s time to start our rails server and see what devise has given us. Run rails server from the command line and lets travel to “localhost:3000/users/sign_up” and see whats going on.

My first thoughts are “Wow, that’s kind of ugly”. haha. Looks like down the line I will have to override those views and build custom ones (by overriding the routes!). I then attempt to sign up by filling out the form. The page reloads and tells me “You have signed up successfully. If enabled, a confirmation was sent to your e-mail.”. Yay, alright now I realize immediatly that I haven’t yet setup an smtp server on my local machine however if we check the server output or logs we will see a generated message:

Sent mail to [email protected] (58ms)
Date: Sat, 08 Jan 2011 12:04:04 -0800
From: [email protected]
To: [email protected]
Message-ID: <[email protected]>
Subject: Confirmation instructions
Mime-Version: 1.0
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: 7bit
<p>Welcome [email protected]!</p>
<p>You can confirm your account through the link below:</p>
<p><a href="http://localhost:3000/users/confirmation?confirmation_token=wYQlv1D1lbB9InFq8dVZ">Confirm my account</a></p>
Sent mail to [email protected] (58ms)Date: Sat, 08 Jan 2011 12:04:04 -0800From: [email protected]: [email protected]: <[email protected]>Subject: Confirmation instructionsMime-Version: 1.0Content-Type: text/html; charset=UTF-8Content-Transfer-Encoding: 7bit
<p>Welcome [email protected]!</p>
<p>You can confirm your account through the link below:</p>
<p><a href="http://localhost:3000/users/confirmation?confirmation_token=wYQlv1D1lbB9InFq8dVZ">Confirm my account</a></p>

Fantastic if we go to the confirmation address http://localhost:3000/users/confirmation?confirmation_token=wYQlv1D1lbB9InFq8dVZ we should be able to active our new account and sure enough the confirm works and sends us to the homepage. It would have been nice to tell the users that they had been confirmed but I guess this is left as an exercise for the developer.

Conclusion

Devise is easy to setup and install using Rails 3. It give me the flexibility and features I need to fulfill the authentication requirements of my application. Good documentation and setup instructions go a long way. We will see with time if I regret my decision. If anyone out there in the internets know of any helpful information that would be beneficial to this blog post please comment below!

Update

To update your Devise views run this from the command line:

rails generate devise:views

This will pull the views from the gem and allow you to modify them.

Rails Test Driven Development Classes on TechTV

Blazing Cloud has partnered with Marakana to record and publish our Efficient Rails Test-Driven Development class. In this video series, instructors Wolfram Arnold and Sarah Allen cover a range of topics from the culture and economics behind TDD to walking students through writing tests first-hand. Students learn best practices for using RSpec, Cucumber, Webrat and Selenium.

Additional topics covered throughout the classes include:

  • Testing in layers, design patterns
  • Toolbox: RSpec with Rails
  • RSpec & Models
  • Testing & Date Dependencies
  • Controller testing
  • View, Helper, Routes Testing
  • Refactoring code & tests, custom matchers
  • API Testing
  • Remote data setup

View all available videos on TechTV.

Efficient Rails TDD is one of the many classes that will be offered at Blazing Cloud’s San Francisco office this winter. To view a complete list of classes visit http://classes.blazingcloud.net