New Series: Rails Application Walkthrough


My wife is a professional photographer with a great eye. She has a natural talent for photography that comes through in her work. Her customers love their pictures, of course, and they love to tell their friends about them. So we had the bright idea to put a page of customer testimonials up on her website. Anyone can bang out a static html page, but where’s the fun in that? Besides, it’s sort of clunky for her to get a quote from a customer, send it to me and then I update the web page. It would be much better if there was some system where a customer, fresh from viewing their online proofs could gush about how wonderful their pictures came out right then and there. Sounds just like a guestbook, doesn’t it? We’ve all seen what happens to them right?

Yup, you guessed it: spam.

What we need is a web app that lets a user submit a testimonial and posts it only when it’s approved. It shouldn’t be hard to write, especially with our new favorite framework, Ruby On Rails.

So let’s get started, er… rolling.

Let’s create our application now:

# rails testimony
...
create  app/controllers/application.rb
create  app/helpers/application_helper.rb
create  test/test_helper.rb
create  config/database.yml
create  config/routes.rb
create  public/.htaccess
create  config/boot.rb
create  config/environment.rb
create  config/environments/production.rb
create  config/environments/development.rb
...
#

Next, let’s create the databases.We’ll need the usual triumvirate - dev, test, prod:

mysql> create database testimony_dev;
Query OK, 1 row affected (0.02 sec)
	
mysql> create database testimony_test;
Query OK, 1 row affected (0.00 sec)
	
mysql> create database testimony_prod;
Query OK, 1 row affected (0.00 sec)
	
mysql> grant all privileges on testimony_dev.* to testimonydb@myhost identified by 'super-secret-password'
Query OK, 0 rows affected (0.00 sec)
	
mysql> grant all privileges on testimony_test.* to testimonydb@myhost identified by 'super-secret-password'
Query OK, 0 rows affected (0.00 sec)
	
mysql> grant all privileges on testimony_prod.* to testimonydb@myhost identified by 'super-secret-password'
Query OK, 0 rows affected (0.00 sec)

0.00 sec? Hey, that’s a snazzy machine I have, no? Next, edit config/database.yml to match the databases and the user we just created. Once that’s done, we need to create our first model.

# ./script/generate model testimonial
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/testimonial.rb
      create  test/unit/testimonial_test.rb
      create  test/fixtures/testimonials.yml
      create  db/migrate
      create  db/migrate/001_create_testimonials.rb

Before we start writing code or defining the schema for our testimonial, let’s stop and think about it for a bit — after all, rapid development doens’t mean thoughtless development. A testimonial, in essence, is a positive statement about someone or something, affirming the value of a product, event or service. It’s made at a particular point in time, by a customer.

class CreateTestimonials < ActiveRecord::Migration
  def self.up
    create_table :testimonials do |t|
      t.column :email,        :string,   :nil => false
      t.column :testimony,    :string,   :nil => false, :limit => 1024
      t.column :approved,     :boolean,  :default => nil
      t.column :created_on,   :date
      t.column :updated_on,   :date
    end
  end
	
  def self.down
    drop_table :testimonials
  end
end

Let’s look at what we’ve got now. We said a testimonial has a who (email), a what (testimony),a when (created_on), and an approval status (approved). Just for auditing, if we care in such a simple application, we’ll use updated_on as the date we approved (or denied) the testimonial. Note that approved is defaulted to nil. This allows us to find entries that have been neither approved or denied. If we had a simple true/false state for approved, we would not be able to tell new testimonials from old, unwanted ones. Makes sense to me. You can go ahead and create the table in the usual fashion, using rake db:migrate

Last thing we’ll do tonight is generate the controller, complete with scaffolding:

# ./script/generate scaffold testimonial testimonial
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/testimonial
      exists  app/views/layouts/
      exists  test/functional/
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
   identical    app/models/testimonial.rb
   identical    test/unit/testimonial_test.rb
   identical    test/fixtures/testimonials.yml
      create  app/views/testimonial/_form.rhtml
      create  app/views/testimonial/list.rhtml
      create  app/views/testimonial/show.rhtml
      create  app/views/testimonial/new.rhtml
      create  app/views/testimonial/edit.rhtml
      create  app/controllers/testimonial_controller.rb
      create  test/functional/testimonial_controller_test.rb
      create  app/helpers/testimonial_helper.rb
      create  app/views/layouts/testimonial.rhtml
      create  public/stylesheets/scaffold.css
#

That wasn’t so bad, was it? Fire up the server, browse to http://testimonials.snowmoonsoftware.com/testimonial and you’ll see the following:

 

Listing testimonials

Email Testimony Approved Created on Updated on

New testimonial

Go ahead and click “New testimonial” and add one. I did:

 

Testimonial was successfully created.

Listing testimonials

Email Testimony Approved Created on Updated on
testuser@testdomain.com This is a “test”-imonial. false 2007-09-05 2007-09-05 Show Edit Destroy

New testimonial

As usual, since we haven’t done anything with the view, it’s ugly. Functional, but ugly. We’ll take care of that at a later date.

Quick recap

What did we accomplish today? We

  1. Staked out our requirements
  2. Generated our application (rails testimony)
  3. Created and configured our databases (mysql create)
  4. Created a stub of our testimonial model (script/generate)
  5. Took a deep breath and thought about the essence of a testimonial and used that to define our model.
  6. Created the table defined by our model (rake db:migrate)
  7. Generated a controller and view with built in CRUD support (script/generate scaffold)

Not too bad, eh?

To be continued…

One Response to “New Series: Rails Application Walkthrough”

  1. [...] Part II: Posted on September 9th, 2007 by Jeff [This is part II of the Testimony Rails Application Walkthrough [...]

Leave a Reply