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

Learn to Build a CMS-Driven Website in a Weekend

Join Blazing Cloud for a weekend workshop on January 22-23rd and learn to build a website that can easily be edited by non-technical people. These days it’s not enough to create a website for someone — we need to provide them tools where they can update text and images, keeping their web presence aligned with their business.

You will learn to use Radiant, an open-sourced content management system (CMS) built with Ruby on Rails. Over the 2 days students will create, customize, and deploy a dynamic website. The workshop is taught by experienced Blazing Cloud engineers, drawing in best practices and lessons learned through their own experience developing with Radiant. The workshop empowers students to go on to build their personal, business or client websites.

Topics Covered:

  • Installing Radiant CMS on your laptop
  • Walk-through of creating Radiant website
  • Deploying to Heroku, a free hosted service
  • Applying custom CSS styling
  • Customizing Radiant using extensions such as Infinite Carousel

Website built during workshop

Radiant WYSIWYG content editor

Those interested in the workshop should be comfortable using web applications, familiar with basic HTML and excited to learn a new technology.

Blazing Cloud is offering Scholarships and an Early Bird Discount. For more information, check out http://classes.blazingcloud.net .


Heroku Migration Fails to Update Attributes: reset_column_information

On several occasions I’ve had Heroku apps fail to recognize columns I add to the database. The symptoms of this problem are:

  • The app throws an error if you visit a page with the new methods referencing the column names
  • If you use heroku console and create your new object it won’t have the attributes for your new column.

This happened to me yesterday and here is how to fix it. First, I made sure that the migration had taken effect. I used the handy heroku sql console plugin which allows you to execute sql on your Heroku database. This allowed me to checkout the schema_migrations table and make sure my latest migration was there:

SELECT * FROM schema_migrations;

Then I looked at the table with the added columns to see if it had the changes:

DESCRIBE courses;

The columns were there.

The reset_column_information method turned out to be the key to fixing this problem:

heroku console
>> Course.reset_column_information

Now Course had the recently added attributes. To avoid this problem next time, I’ll use reset_column_information inside of the migration when I change an existing model’s attributes. An additional facet to this solution is that if you access a model class in a migration, you need to open up the class in the migration:

  class Course < ActiveRecord::Base; end

Here are some resources:

Caching in Rails

In Rails we have two different ways of Caching

- Page Caching: which is always stored on Disk
- Action & Fragment Caching: which uses the configure cache configured in our Rails instance.

By default Rails provides three techniques:

1) Page Caching

Allows the request for a generated page to be fulfilled by the webserver, without ever having to go to your RoR application.

In other words if you have page caching turned on,  the request will come in, go to Mongrel, the page will then be generated, and then sends  it back to apache.  Additionally,  it will be stored in a local file system. Next time we request the same page, apache will load the page from the filesystem and send it back to the client, without your Rails application being called at all.

To turn on page caching you need to make sure  “perform_caching” is set to true for your environment.  This flag is normally set in the corresponding config/environments/*.rb

By default, caching is disabled for development and test, and enabled for production.

config.action_controller.perform_caching  = true

The next step is to cache the action(s) in the controller by using the page-caching approach that will store the cache in a path.

caches_page :index, :show

Page Cache options

We can cache any  filesystem format (json, xml, iphone) by using the Rails response format.

The page caching mechanism will automatically add the appropriate corresponding extensions: /public/users.html; public/users.xml; public/users.json; public/users.iphone.

By default it gets cached under public/<name>.html. Changing the default helps avoid naming conflicts, since we put static html in public/. To do this, it will require web server reconfiguration to let the web server know from where to serve the cached files .

Rails::Initializer.run do |config|
   config.action_controller.page_cache_directory = "#{RAILS_ROOT}/public/cache"
...
end

Quick Tips

Page caching ignores all parameters, so if your request is http://mysite.com/users?page=1, it will be written out as public/users.html.  A request like http://mysite.com/users?page=3, will be served as users.html. To avoid this you might consider  changing your routes.rb

2) Action Caching

Action caching works like page caching except that the incoming web request goes from the web server to the Rails apps. It does this so that before_filters can be run before the cache file is served. This allows you to use authentication and other restrictions while still serving the results of the request from a cached copy.

We want to use action caching while running “filters” or executing code in the views, but remember the content is always the same. So in your controller you will call :

caches_action   :show

before_filter :autenticate, :only => [:show]

Action Caching Options

You can set different ways of cachings in /config/environments/development.rb

config.cache_store = :file_store, ‘tmp/cache’
config.cache_store = :memory_store, which basically is {} in memory (background).
Note:
- You can run out of memory
- There no sharing between processes. You cannot use it if you run more than one instance of your rails apps.

Including different options such as:config.cache_store = :mem_cache_store

share apps: config.cache_store = :mem_cache_store, :namespace => “store”
multiple servers: config.cache_store = :mem_cache_store, 192.168.1.255:1001, 192.168.1.255:1002
config.cache_store = :drb_store
  • as custom_store

config.cache_store = :drb_store

To use action caching, add the method caches_action: <action> to your Controller

Features

1. Cache the action without the layout.

class PostsController < ApplicationController
    caches_action :index, :show
    before_filter :autenticate, :only => [:show], :layout => false
 .......
end

It will only cache your action content. Note: If you need some sort of data you might want to use before_filter and set you instance variables.

2. Conditional Action action using :if (or :unless) => Proc.new{….} to specify when the action should be cached.

3. Specific path using :cache_path => Proc.new { |controller| ….} or
:cache_path => {:expires_in =>1.hour }, to specify when the action should be cached. (only with memcached & rails > 2.1)

3) Fragment Caching

Fragment caching allows you to fragment many pieces of the view. The pieces will be wrapped in a cache block and served out of the cache store when the next request comes in. Fragment caching is useful for dynamic web applications.

When the same request comes in again, we pull the different pieces out of the cache, combine them into a single page, and send it back to the client.

To implement fragment caching, cache your method  in the view:

<% cache (:recent_joined) do %>
    <% @recent_joined.each do |user| %>
.........
    <% end %>
<%end>

And you will see the fragment key in the log, which are prefixed with “views/”

Memcached

I thought there was some kind of fancy voodoo happening, but it turns out that it’s basically just a hash! Memcached is simply a key value stored in memory, no voodoo here.

To implement just set your cache in,/config/environments/production.rb
config.cache_store = :mem_cache_store

Same thing as config.cache_store = :memory_store, but it runs as a separate process. You can have several rails instances that reference the same memcached instance.

Note: Please make sure to install the gem memcached in your environment.

Rails automatically creates a global cache during initialization and you can access this in your code either using Rails.cache or the RAILS_CACHE global variable.

We can use memcached  as  a fragment cache store or an object store.

Action & Fragment Caching

If we look into our memcached process we can see the keys that are getting stored inside the memcached. Then if we refresh our page we can see that the cached fragments are  getting pulled.

Object Store

You can access the cache stores for storing queries strings

Rails.cache.read("name") # => nil
Rails.cache.write("name", "Bill")
Rails.cache.read("name") # => "Bill"
Rails.cache.exist?("name") # => true


Or objects

Let’s say we have @recent_joined variable in the UsersController#index

def index
    @users = User.paginate :page => params[:page], :order => 'created_at DESC'
    @recents_joined = User.find( :all, :order =>'created_at DESC',
                                 :limit => 2) unless fragment_exist? :recents_joined
    respond_to do |format|
      format.html #default index.html
      format.xml { render :xml => @users }
    end
  end

Rails.cache.read(‘views/recent_joined’)

Then in the memcached server memcached -vv
We can see that when the key exists, Rails.cached.read() and Rails.cached.exist?() are doing a get of the key and sending it back. When Rails.cache.delete(), the server is confirming the deletion of the key.
When it doesn’t exist it ends.

Some  additional points to keep in mind:

- Expire at

def self.recent
    Rails.cache.fetch("recent_posts", :expires_in => 30.minutes) do
       self.find(:all, :limit => 10)
    end
end

Run this query every 30 minutes…

-   You don’t need to have memcached installed to develop locally.
You will get MemCacheError (No connection to server): No connection to server Cache miss:
But, your app will work just fine. Rails will always execute the contents of the fetch blocks, and will return nil for any reads.

Expiring cached pages

Everybody knows that expiring cached pages is like pulling teeth, but regretfully it is something that we all need to do.

One’s first inclination may be to expire pages in the Controller and usually via the update method. Depending on which technique you choose to expire pages you can use the method expire_page {action,fragment}
However, instead of having expired methods around your controllers to clear cache files based on when a model is updated, sweepers are definitely the way to go.

ActionController::Caching::Sweeper class. (Share Objects)

This class is an observer that looks for changes to an object via callbacks, and when a change occurs it expires the caches associated with that object in and around or after filters. The sweeper observes controllers and models.

Hooks:
Any observer callbacks

  • after create
  • after destroy
  • after_save, etc.

Also in any controllers callbacks

  • before/after_<controller_name>
  • before/after_<controller_name>_<action>

To implement sweepers there are four primary steps.
1) Declare the following load path config.load_paths << “#{RAILS_ROOT}/app/sweepers” in /config/environment.rb. This will keep the sweepers separate from models and controllers.

2) Create the sweepers folder, which contains the observed files.

3) Create the observed files
Note: The observed file should look like the following example:

We can see in the log that the observe gets triggered when a new user is created.



Another way to expire

If we want to avoid using Sweeper we can clear the cache in the model. The following is an example of clearing the cache in the model:


Note: This can also be used in a cron job.

Some Thoughts

* Implementing page caching can be easy. However, expiring can be prove to be a bit more challenging .
* I find testing kind of tricky.
* I read through numerous blog posts but I couldn’t quite figure out how to get things to work as I hoped.
* The following are alternatives I’ve recently used:

* Custom Matches by overwriting the matches? method (ActionController::Caching::Actions)

* Build your CachePage / Fragment Page class and use

ActionController::Base.expire_page( )

ActionController::Caching::Fragments.

expire_fragment
fragment_cache_key
fragment_exist?
read_fragment
write_fragment

32- or 64-bit Ruby?

For the most part Ruby abstracts the architecture of the machine, but sometimes you need to know quickly and easily when you are installing components.  So… how do you tell in Ruby if you are on a 64-bit architecture? I like this concise answer best:

>>  (-1).size

If this evaluates to 8 you are on a 64-bit architecture.  If it is 4, it is 32-bit.

PeerPressure Available Now on the App Store!

PeerPressure Video

Blazing Cloud and Lucky Knives are excited to announce the official release of PeerPressure, an iPhone application that creates a virtual support group to help you meet your goals.

Choose from over 250 goal templates ranging from “Be Happier” to “Write a Book” or create your very own. PeerPressure draws in your friends via Twitter, Facebook, and email for positive support. Achieve one of your milestones? PeerPressure will send out a notification of your success to your friends. Forget to update or miss one of your milestones? PeerPressure will alert your friends that a bit of encouragement is needed to get you back on track. Queue up as many goals as you like while focusing on your main objective. Every time you start a goal, a custom webpage is created to help you and your friends chart your goal’s progress.

Over the past month, we’ve been testing PeerPressure at Blazing Cloud to see how a bit of peer pressure can push us to meet our goals. Our fearless founder Sarah invited us to track her goal of creating notes for programmers starting out in Rails 3. As she met her milestones, we received updates on her progress  and cheered her on.

This week, I’ll invite my friends to track my progress as I get back into running. Follow my progress at twitter.com/billdevine and send some peer pressure.

Visit the App Store today to download PeerPressure and start achieving your goals.

For Additional information visit PeerPressure visit http://www.peer-pressure.com/