Tracking Your Rdoc Coverage with RdocMetric

September 10, 2009

I was surprised when I didn’t find a Ruby gem that would analyze your code and give you a metric for how thorough your Rdoc documentation was. Since I want to keep myself accountable to keeping code documented, I whipped up the rdoc_metric gem. So far it is very simple, giving you percentages of how many of your class, module, method, attribute and constant declarations are documented using Rdoc.

Usage is simple, just cd into your application directory and use the rdoc_metric command:

cd ~/apps/my_app
rdoc_metric

Or, if you want to get specific and only get metrics for a specific directory of your app (say, your models):

cd ~/apps/my_app
rdoc_metric app/models

Download it here on GitHub


Delayed Method Chaining

July 14, 2009

Usually alias_method_chain does a great job when you need to monkey patch some code. One limitation, however, is that both the original method and the hack method must be defined before using alias_method_chain. This is rarely an issue, but it does come into play if you ever want to chain methods to an ActiveRecord column getter/setter. These methods are added on the fly, so you have no access to them within your model class.

Now you can simply use delayed_method_chain:

# has a :price column
class Product < ActiveRecord::Base
  require 'delayed_method_chain'
  delayed_method_chain :price=, :formatting
  # quick formatting
  def price_with_formatting=(amt)
    price_without_formatting = amt.to_s.gsub(/[^0-9\.]/, '').to_f.round(2)
  end
end

You can download the code, or alter the gist on GitHub if you have ideas on how to improve it!


Ruby Gems vs. Rails Plugins

May 24, 2009

A point of some confusion to a developer learning Ruby on Rails is the difference between using gems and plugins. They both offer out-of-the-box, third party functionality, and yet they have remarkable differences. Thanks to GitHub it’s very easy to write, host and share your own gems and plugins, so here is a quick review of their differences.

Rails Plugins

The Ruby on Rails framework comes with a specific architecture for loading plugins that can change and augment your application and the Rails framework itself. When your Rails app is loaded, this is the order in which code is loaded:

  1. The Rails framework is loaded (either from vendor/rails or the Rails gems).
  2. All plugins are loaded from vendor/plugins.
  3. Your application code in app and lib is loaded.

Because of this order, plugins can use code in the Rails framework, it can override the framework, and then it can be used within your application code.

Plugins must live in vendors/plugins, so the installed code will be localized in your code repository. The good news is that should you need to alter the plugin in any way, you can go in and hack away at the code without affecting your other apps. Unfortunately, your favorite plugin will have to be installed each time you create a new app (unless you’re using the new Rails Templates).

Rails plugins have the flexibility to hook into every part of Rails, including generators, rake tasks and tests/specs. They are specific to Rails, however, and could not be (directly) used with another Ruby framework (Merb, Sinatra, etc.). Personally, I think that any functionality that solely extends the Rails framework should always be a plugin rather than a gem, simply because that gem couldn’t be used outside of Rails anyways.

Ruby Gems

Gems are a facility of the Ruby language and have no dedicated connection to the Rails framework. Ruby gems are highly portable chunks of Ruby code that can be used inside any Ruby script or application. Thanks to its distributed architecture, one quick ‘gem install’ command can search RubyForge, GitHub and other repositories at the same time so that you don’t need to know where that gem lives to install it.

Gems are saved on your machine once and then included into applications using ‘require’. Naming conventions can be tricky, however, when gems are stored on GitHub or when the author did not stick to regular conventions. For example, this will install my iTermWindow gem from GitHub:

sudo gem install chrisjpowers-iterm_window

To use the gem in code, however, it looks like this:

require 'rubygems'
require 'iterm_window'

Regardless, RubyGems make it very easy to make functionality available in all your Ruby apps and scripts. It is important, though, to make sure that you have all the correct gems installed on all your development machines and staging/production servers, and that they all are using the same versions of the gems.

To avoid the problem of missing dependencies, Rails gives you a rake task to copy the gem files locally in your project in vendor/gems. Your gems will be saved in your repository and distributed along with your app when you use this task:

rake gem:unpack

Please note that this will not work for all gems — some gems have more complex C bindings and native extensions that cannot be unpacked into vendor.

Different Tools for Different Jobs

While Ruby gems and Rails plugins have similar effects in your application, they obviously vary significantly in their architecture. Ultimately, each will prove more or less useful in a given scenario. As I mentioned before, my rule of thumb is to make Rails-specific functionality a plugin while making more general Ruby libraries into gems.

So now that you know the differences, get onto GitHub and start sharing some code!


Safely Using Production Assets in Staging

May 1, 2009

There are well over 100GB of image assets in the production deployment of the Web app I am currently developing. Since I’m using a full dump from the production database for my staging database, I need my staging environment to use all the same assets as well. The last thing I want to do is to copy the 100GB+ of images into my staging environment.

Simply sharing the assets between production and staging sounds easy, but there are caveats. I have to make sure that anything I do in staging (for example, deleting image assets) does not affect the production environment. To achieve this, I added this hack to my staging nginx config:

# Concatenate results of following if statements
set $image_hack "";

# Mark if an image is requested
if ($request_filename ~* .(css|jpg|gif|png)$) {
  set $image_hack I;
}

# Mark if the static file is not found
if (!-f $request_filename) {
  set $image_hack "${image_hack}F";
}

# If the request is for an image that is not found, redirect to production
if ($image_hack = IF) {
  rewrite ^/(.*) http://production.mysite.com/$1 permanent;
  break;
}

This admittedly seems like a lot of code, but nginx seems to lack the ability to conditionally test if (this AND that). With this hack in place, any CRUD actions on assets will be performed locally, while requested images first be found locally, then proxied to production.


Super Easy Number Tracking with FatNum.com

March 16, 2009

What’s Your FatNum?

Numbers are a big deal. Whether you’re talking about business, family, fun, personal goals, a lot can be simply boiled down to one big, fat number…

  • How many people registered for my app?
  • How many batches are left in my database import?
  • How many days left until my birthday?
  • How many pounds have I lost on my diet?
  • And so on…

So what’s the big, fat number that you need to keep track of? Whatever it is, FatNum.com can help.

What is FatNum.com?

FatNum.com lets you signup and start tracking your FatNums right now! Right away you are given a simple Web interface for creating your FatNums and keeping them up to date. Each FatNum is assigned a five-character code, so you can share your FatNum with others discreetly without having to log in.

For all you programmers who want their Ruby apps to share data with FatNum.com, I’ve built this RubyGem for easily accessing and updating your FatNums. From the documentation:

require 'rubygems'
require 'fat_num'

f = FatNum.new('your@email.com', 'password')

# get your statistic
response = f.get('e37gh')
response.digit #=> 120

response.description #=> 'batches left'

# update your statistic
f.update('e37gh', 119)

# sure enough, our update was successful
f.get('e37gh').digit #=> 119

There’s also some love for all you Mac users out there — download the FatNum Dashboard Widget and easily track your FatNums from the comfort of your OSX Dashboard!

Any More Examples?

Here are a couple FatNums that FatNum.com is using for itself:

FatNum.com is super simple, almost to a ridiculous degree, but I hope you can find some imaginitive uses for it!


Introducing FlexibleCSV

February 19, 2009

Get FlexibleCSV from GitHub

A Challenge in Flexibility

As part of a contact management system we are building for a client, I encountered a unique challenge with allowing users to upload and import their contacts from CSV files. Usually this would not be a problem, except that in this case there was no standardization to what the header names would be or what order the columns were in. Because the FasterCSV gem relies on using the header names as access keys, this process was suddenly quite complicated.

One solution would be to create a user interface that would display our database fields, their CSV columns and allow them to pair them up. For example, my database column is ‘email’ but their CSV column is ‘Email Address’, so they could mark those as equivalent. What would I do, however, for the users who have a “Full Name” column when I use ‘first_name’ and ‘last_name’ database columns? Suddenly the user interface could get very complicated and confusing.

Introducing FlexibleCSV

Instead, I developed FlexibleCSV, a gem that allows you to parse through a CSV file without knowing exactly what the headers are named. By providing a list of possible header names, you can access all the CSV columns with a uniform interface.

require 'flexible_csv'

# Arbitrary CSV data
csv_data1 = %Q{Full Name, Email AddressnJohn Doe, john@doe.com}
csv_data2 = %Q{Email, Namenjohn@doe.com, John Doe}

parser = FlexibleCsv.new do |csv|
  csv.column :full_name, "Name", "Full Name", "Client Name"
  csv.column :email, "Email", "Email Address"
end

parser.parse(csv_data1).each do |row|
  puts row.full_name #=> 'John Doe'
  puts row.email     #=> 'john@doe.com'
end

parser.parse(csv_data2).each do |row|
  puts row.full_name #=> 'John Doe'
  puts row.email     #=> 'john@doe.com'
end

Both data sets can now be accessed using the uniform #full_name and #email accessors.

Handling Complexity with Adapters

Going back to my original example, how would we handle CSV files that separated first and last names when my database uses the full name? Or vis versa? Though I considered adding this kind of functionality to the FlexibleCSV gem, ultimately I thought it best to keep that kind of logic in a separate adapter class. For example:

require 'flexible_csv'

# Arbitrary CSV data
csv_data1 = %Q{Full NamenJohn Doe}
csv_data2 = %Q{First Name, Last NamenJohn,Doe}

parser = FlexibleCsv.new do |csv|
  csv.column :full_name, "Name", "Full Name", "Client Name"
  csv.column :first_name, "First Name", "First"
  csv.column :last_name, "Last Name", "Last", "Surname"
end

class CsvAdapter
  def initialize(row)
    @row = row
  end

  def full_name
    row.full_name || "#{row.first_name} #{row.last_name}"
  end

  def last_name
    row.last_name || row.full_name.split(' ').last
  end

  def first_name
    row.first_name || row.full_name.split(' ').first
  end

  def method_missing(method_name, *args)
    row.send(method_name, *args)
  end
end

parser.parse(csv_data1).each do |row|
  ad_row = CsvAdapter.new(row)
  puts ad_row.full_name  #=> 'John Doe'
  puts ad_row.first_name #=> 'John'
  puts ad_row.last_name  #=> 'Doe'
end

parser.parse(csv_data2).each do |row|
  ad_row = CsvAdapter.new(row)
  puts ad_row.full_name  #=> 'John Doe'
  puts ad_row.first_name #=> 'John'
  puts ad_row.last_name  #=> 'Doe'
end

Using the adapter class, we can once again access each row of data from any CSV file with a uniform interface.

Go Get It!

To use the FlexibleCSV gem, you can follow or fork the project on GitHub or just install the gem:

sudo gem install chrisjpowers-flexible_csv

Organized Logs with LogCabin

December 30, 2008

While optimizing our Rails apps, I used the standard Rails Logger to output performance information about specific trouble-spots of code. Having to constantly grep through the production log, however, was driving me nuts. What I really wanted to do was to write information about a specific problem area to a specific file, without adding a lot of extra code.

And now the LogCabin Rails plugin makes this very easy (Get it on GitHub).

The LogCabin plugin is designed to give you the flexibility to
write information about blocks of code and their execution times to
specific log files in your Rails project. LogCabin can also be used in Rake tasks, which can be incredibly helpful for debugging and monitoring long-running tasks.

Example Usage

This is especially useful when monitoring and debugging a specific set of
code in a model or controller file. As a contrived example:

class UsersController < ApplicationController
  def index

    LogCabin.log_to :user_search do |log|
      log.debug "Finding all users with params = '#{params[:user_search].map{|k,v| "#{k}: #{v}"}.join(', ')}'"

      @users = User.search(params[:user_search])
      log.info "Found a total of #{@users.length} users"

      log.warn "ONLY FOUND #{@users.length} USERS" if @users.length < 50

    end
  end
end

LogCabin logs the time it took to run the block, along with any info, debug or warn messages that you ran on the log object. This code might print the following out to RAILS_ROOT/log/user_search.log:

DEBUG: Finding all users with params = 'last_name: Smith, city: Chicago'
INFO: Found a total of 32 users
WARN: ONLY FOUND 32 USERS
TIME: Tue Nov 18 12:34:52 -0600 2008: Operation took 3.2876 seconds

It is also possible to pass an :if or :unless option to LogCabin#log_to, ex:

LogCabin.log_to :users_query, :if => RAILS_ENV == 'development' do |log|

  log.info "This will not output anything unless we're in development"
  puts "But any other Ruby code in this block will always be run"
end

Leveraging Capistrano

I think one of the best parts about using LogCabin is how easy it is to check up on these logs across multiple production servers using Capistrano. Here’s a cap task that will let you tail a specific log or monitor the live stream:

# Assumes the deploy_to variable has been set in your Capistrano config
namespace :deploy do
  namespace :log do

    desc "Tails a log "
    task :tail, :roles => [:app] do

      set(:log_name) do
        Capistrano::CLI.ui.ask "Which log do you want to fetch? "

      end
      set(:line_count) do
        Capistrano::CLI.ui.ask "How many lines should I fetch? (blank to tail log) "

      end
      if line_count.strip! =~ /^d+$/

        run "tail -n #{line_count} #{deploy_to}/current/log/#{log_name.gsub(/.log$/, '')}.log"
      else
        run "tail -f #{deploy_to}/current/log/#{log_name.gsub(/.log$/, '')}.log"

      end
    end
  end
end

Download LogCabin from GitHub


DRY Up Forms with Custom Form Builders

November 21, 2008

Revisiting Our Form

Continuing with the example from my last article, I have this simple form:

<% form_for :product, :url => products_path do |f| %>

  <div class="form_item text_field">
    <label for="product[name]">Name:</label>
    <%= f.text_field :name %>

  </div>
  <div class="form_item text_field">
    <label for="product[price]">Price:</label>
    <%= f.text_field :price %>

  </div>
  <div class="form_item text_field">
    <label for="product[features]">Features (1 per line):</label>
    <%= f.text_area :features %>

  </div>
  <div class="form_item submit_button">
    <%= f.submit "Create Product" %>
  </div>

<% end %>

Note: I changed the original form’s wrapper tags from <p> to <div>. The reason is that, if you’re using the built-in Rails error message helpers, by default it will wrap erroneous fields in <div> tags. Since <div> tags can’t nest within <p> tags, this can cause serious layout-breaking problems.

There’s a lot of duplication here in terms of the wrapper code. Each field is wrapped in a <div> with a class of form_item as well as a descriptor of what kind of field it contains. I use this information for CSS styling of specific kinds of inputs. The labels are also fairly repetitive as well, and these repetitions would become more obnoxious were this a longer form.

Removing Repetition

What if we could generate this same form code while removing the repetition? It’s possible, and Rails gives us a great hook for just this scenario by allowing us to build custom Form Builders. A custom Form Builder is simply a subclass of ActionView::Helpers::FormBuilder that can alter and extend the abilities of the regular Form Builder. In our current form, the f block variable is an instance of FormBuilder, so methods like text_field and submit are all instance methods of the FormBuilder class. Let’s override these methods to not only output the field markup, but to also output the wrapper div:

# in /helpers/application_helper.rb
class WrapperFormBuilder < ActionView::Helpers::FormBuilder
  METHODS_TO_OVERRIDE = %w{text_field text_area password_field file_field date_select datetime_select submit}

  METHODS_TO_OVERRIDE.each do |method_name|
    src =<<END_SRC

      def #{method_name}_with_wrapper(field, options={})
        # allow explicit setting of label text with options[:label]
        field_label = if '#{method_name}' == 'submit'
          '' # no label for submit inputs
        elsif options[:label]
          label(field, options.delete(:label))
        else
          label(field) + ":" # Adds colon as default
        end

        # get unwrapped field
        field_markup = #{method_name}_without_wrapper(field, options)

        # return wrapped field (@template gives us access to helper methods in this class)
        @template.content_tag(:div, field_label + field_markup, :class => "form_item #{method_name}")
      end
    END_SRC

    class_eval src, __FILE__, __LINE__
    alias_method_chain method_name.to_sym, :wrapper

  end

end

For our form, we can now implement our new class like this:

<% form_for :product, :url => products_path, :builder => WrapperFormBuilder do |f| %>

Another possibility is to create a new method to replace form_for:

# in helpers/application_helper.rb
def wrapper_form_for(name, object=nil, options={}, &proc)

  form_for(name, object, options.merge(:builder => WrapperFormBuilder), &proc)

end

Using this new helper method, our form now looks like this:

<% wrapper_form_for :product, :url => products_path do |f| %>

  <%= f.text_field :name %>
  <%= f.text_field :price %>

  <%= f.text_area :features, :label => "Features (1 per line):" %>

  <%= f.submit "Create Product" %>
<% end %>

If you need to create a form field without a wrapper (perhaps to use a non-conforming wrapper), you can still access the original methods like f.text_field_without_wrapper or f.submit_without_wrapper.

I have found custom Form Builders to be powerful tools for speeding up form development, DRYing up code and keeping consistency between forms and developers. This is a fairly basic example, but the sky is the limit for what you can implement using these techniques.


Pretty Data, Pretty Code

November 14, 2008

In my last article I wrote about using data modeling to clean up form-related code and to take advantage of powerful helpers like form_for and error_messages_for. This solves the significant problem of isolating business logic into a model class, but another problem remains — how can we make our form data pretty without trashing our model’s code with view logic?

Beautifying the Data

I have a simple Product model with rows for name, price and features. Setting and displaying the price field is tricky because I need to remove currency formatting before storing it in the database as a decimal, and I want to reformat it when displaying the current price in an ‘Edit’ form. The features field is also tricky. I want the user to enter each product feature (“Slices and Dices”, “Purees Anything”, etc.) on a separate line of the textarea and for that to be split into a serialized array that I will store in the database.

My first instinct is to create virtual attributes in my model to handle the logic of deformatting/reformatting this data. Here’s how it looks:

class Product < ActiveRecord::Base
  serialize :features, Array

  validates_presence_of :name
  validates_numericality_of :price

  # need this for formatting
  def helpers

    ActionController::Base.helpers
  end

  def price_field=(p)

    # expecting p to be something like "$4,000.00", set price to 4000.00
    p.gsub!(/[^0-9.]/, '')
    self.price = p.to_f

  end

  def price_field
    helpers.number_to_currency(self.price)

  end

  def features_field=(str)
    # expecting string with features separated by newlines
    self.features = str.split("n").collect {|f| f.strip }

  end

  def features_field
    self.features.join("n")

  end
end
<%# the product form %>
<% form_for :product, url => products_path do |f| %>

  <p class="form_item text_field">
    <label for="product[name]">Name:</label>
    <%= f.text_field :name %>

  </p>
  <p class="form_item text_field">
    <label for="product[price_field]">Price:</label>
    <%= f.text_field :price_field %>

  </p>
  <p class="form_item text_field">
    <label for="product[features_field]">Features (1 per line):</label>
    <%= f.text_area :features_field %>

  </p>
  <p class="form_item submit_button">
    <%= f.submit "Create Product" %>
  </p>

<% end %>

The good news is that we have a very simple, straightforward looking view with no logic stuffed in it. Our controller is also completely vanilla, so I didn’t bother to even show it.

Our model, however, is getting cluttered. What once was a haven for business logic is now filled with both business and view logic. I’m also a little concerned about having to use the #price_field and #features_field methods, since it adds complexity to what should be a simple object API. Will this cause confusion with my fellow programmers?

Beautifying the Code

What if we extracted the view logic into its own object? By using a presenter object as an adapter between our Product model and our form we can isolate the view logic from the business logic. Here’s how it looks:

class Product < ActiveRecord::Base

  serialize :features, Array

  validates_presence_of :name
  validates_numericality_of :price

end
class ProductPresenter
  attr_reader :product

  def initialize(product)

    @product = product
  end

  # need this for formatting
  def helpers

    ActionController::Base.helpers
  end

  # for mass assignment
  def attributes=(hash)

    hash.each_pair do |key, val|
      self.send("#{key}=".to_sym, val)

    end
  end

  def price=(p)
    # expecting p to be something like "$4,000.00", set price to 4000.00

    p.gsub!(/[^0-9.]/, '')
    @product.price = p.to_f

  end

  def price
    helpers.number_to_currency(@product.price)

  end

  def features=(str)
    # expecting string with features separated by newlines
    @product.features = str.split("n").collect {|f| f.strip }

  end

  def features
    @product.features.join("n")

  end

  # proxy all other methods to @product
  def method_missing(method_name, *args, &block)

    @product.send(method_name, *args, &block)
  end

end
class ProductsController < ApplicationController
  def new
    @product = ProductPresenter.new(Product.new)

  end

  def edit
    product = Product.find(params[:id])

    @product = ProductPresenter.new(product)
  end

  def create

    @product = ProductPresenter.new(Product.new)
    @product.attributes = params[:product]

    if @product.save
      # success
    else
      render :action => 'new'

    end
  end

  def update
    p = Product.find(params[:id])

    @product = ProductPresenter.new(p)
    @product.attributes = params[:product]

    if @product.save
      # success
    else
      render :action => 'new'

    end
  end
end
<%# the product form %>
<% form_for :product, url => products_path do |f| %>

  <p class="form_item text_field">
    <label for="product[name]">Name:</label>
    <%= f.text_field :name %>

  </p>
  <p class="form_item text_field">
    <label for="product[price]">Price:</label>
    <%= f.text_field :price %>

  </p>
  <p class="form_item text_field">
    <label for="product[features]">Features (1 per line):</label>
    <%= f.text_area :features %>

  </p>
  <p class="form_item submit_button">
    <%= f.submit "Create Product" %>
  </p>

<% end %>

Our business and view logic have been effectively separated, our form code is clearer and the controller is only slightly more complicated. Because the ProductPresenter is acting as a proxy object to its Product object, we can simply treat it like a product thanks to ‘duck typing’. While this example is a little contrived, using presenter classes can make or break your code base as you create complex model objects with equally complex visual representations.


Modeling All Form Data

November 7, 2008

Forms of Every Shape and Color

As the Web continues to develop as an interactive, read/write medium, web forms are more useful and necessary than ever. Historically speaking, forms tend to be difficult for developers — validation, error handling, field population, redirection, data modeling and storage, these all play a part in even the simplest forms.

In the Rails world, our lives were made significantly easier thanks to the form_for helper. With this helper method, the Rails developer gets a lot for free thanks to its interaction with the ActiveRecord object that is being manipulated. Between ActiveRecord validation and the intelligent field population of form_for, creating forms becomes nearly trivial.

But what about the other forms, those that are not directly manipulating an ActiveRecord object? Forms like ‘Log In’ and ‘Search’ forms? If the developer is not using the form to CRUD an ActiveRecord model instance, he suddenly finds himself back to using low level helpers like text_field_tag and enforcing validation and other business logic within the controller.

But There’s a Better Way!

All data that we receive from forms should be modeled, but we don’t always have to use an ActiveRecord model class to do it. For data that needs to be modeled but not stored in the database, we can simply use a plain ol’ Ruby class. Let’s say that we want to create a login form – it will have fields for email and password, and a checkbox for “Remember Me”. We can model this data like so:

<!–

# app/models/login.rb
class Login
  attr_reader :email, :password, :remember_me
  def initialize(params = {})
    @email = params[:email]
    @password = params[:password]
    @remember_me = params[:remember_me]
  end

  def authenticate
    # tie into User model for authentication
    user = User.authenticate(self.email, self.password)
    return user
  end
end

–>

# app/models/login.rb
class Login
  attr_reader :email, :password, :remember_me

  def initialize(params = {})
    @email = params[:email]

    @password = params[:password]
    @remember_me = params[:remember_me]

  end

  def authenticate
    # tie into User model for authentication
    user = User.authenticate(self.email, self.password)

    return user
  end
end

<!–

# app/controllers/sessions_controller.rb
class SessionsController  'new' # unsuccessful login
    end
  end
end

–>

# app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  def new
    @login = Login.new

  end

  def create
    @login = Login.new(params[:login])

    if current_user = @login.authenticate
      redirect_to successful_login_path
    else

      render :action => 'new' # unsuccessful login
    end
  end

end

<!–

<%# app/views/sessions/new %>
<% form_for :login, :url => sessions_path do |f| %>
  <p class="form_item">
    <label for="login[email]">Email</label>
    <%= f.text_field :email %>
  </p>
  <p class="form_item">
    <label for="login[password]">Password</label>
    <%= f.password_field :password %>
  </p>
  <p class="form_item">
    <label for="login[remember_me]">Remember Me</label>
    <%= f.check_box :remember_me %>
  </p>
  <p class="form_item submit_button">
    <%= f.submit "Login" %>
  </p>
<% end %>

–>

<%# app/views/sessions/new %>
<% form_for :login, :url => sessions_path do |f| %>

  <p class="form_item">
    <label for="login[email]">Email</label>
    <%= f.text_field :email %>

  </p>
  <p class="form_item">
    <label for="login[password]">Password</label>
    <%= f.password_field :password %>

  </p>
  <p class="form_item">
    <label for="login[remember_me]">Remember Me</label>
    <%= f.check_box :remember_me %>

  </p>
  <p class="form_item submit_button">
    <%= f.submit "Login" %>
  </p>

<% end %>

A Dash of Validation

The good news is that we have modeled the login data and now have a place other than the controller for login-specific logic. We are still missing validation, however. If our Login class doesn’t inherit from ActiveRecord, does that mean we need to roll our own validation methods?

Thankfully Jay Fields already did the work for us by creating the Validatable Ruby gem (sudo gem install validatable). The Validatable module can be mixed into any Ruby class and provides the same validation interface that we are accustomed to using with ActiveRecord. Now we can require both the email and password to be filled out before we even try attempt a login. Here’s our updated code:

<!–

# app/models/login.rb
class Login
  include Validatable

  validates_presence_of :email, :password

  attr_reader :email, :password, :remember_me
  def initialize(params = {})
    @email = params[:email]
    @password = params[:password]
    @remember_me = params[:remember_me]
  end

  def authenticate
    # tie into User model for authentication
    unless user = User.authenticate(self.email, self.password)
      self.errors.add(:base, "No user was found with that email and password.")
    end
    return user
  end
end

–>

# app/models/login.rb
class Login
  include Validatable

  validates_presence_of :email, :password

  attr_reader :email, :password, :remember_me
  def initialize(params = {})

    @email = params[:email]
    @password = params[:password]

    @remember_me = params[:remember_me]
  end

  def authenticate

    # tie into User model for authentication
    unless user = User.authenticate(self.email, self.password)

      self.errors.add(:base, "No user was found with that email and password.")
    end
    return user

  end
end

<!–

# app/controllers/sessions_controller.rb
class SessionsController  'new' # unsuccessful login
    end
  end
end

–>

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController

  def new
    @login = Login.new
  end

  def create

    @login = Login.new(params[:login])
    if @login.valid? && current_user = @login.authenticate

      redirect_to successful_login_path
    else
      render :action => 'new' # unsuccessful login

    end
  end
end

<!–

<%# app/views/sessions/new %>
<%= error_messages_for :login %>
<% form_for :login, :url => sessions_path do |f| %>
  <p class="form_item">
    <label for="login[email]">Email</label>
    <%= f.text_field :email %>
  </p>
  <p class="form_item">
    <label for="login[password]">Password</label>
    <%= f.password_field :password %>
  </p>
  <p class="form_item">
    <label for="login[remember_me]">Remember Me</label>
    <%= f.check_box :remember_me %>
  </p>
  <p class="form_item submit_button">
    <%= f.submit "Login" %>
  </p>
<% end %>

–>

<%# app/views/sessions/new %>

<%= error_messages_for :login %>
<% form_for :login, :url => sessions_path do |f| %>

  <p class="form_item">
    <label for="login[email]">Email</label>
    <%= f.text_field :email %>

  </p>
  <p class="form_item">
    <label for="login[password]">Password</label>
    <%= f.password_field :password %>

  </p>
  <p class="form_item">
    <label for="login[remember_me]">Remember Me</label>
    <%= f.check_box :remember_me %>

  </p>
  <p class="form_item submit_button">
    <%= f.submit "Login" %>
  </p>

<% end %>

Our Login class now can use the familiar validates_* class methods, the valid? instance method and all the facilities that come with having the errors object (like using error_messages_for).

It also becomes very easy to set default values for the login form. For example, if we wanted to ‘check’ the Remember Me box by default, we could simply change our SessionsController#new action to this:

def new
  @login = Login.new(:remember_me => true)

end

Modeling our form data in this way is a win-win scenario — we’re using good coding practices by keeping business logic out of our controller, and we’re also inheriting all the facilities that Rails provides by leveraging form_for, error_messages_for and validations.