command line happiness

How could I have lived for so long without knowing that I could set up my command line with vi key bindings? Well, for anyone else who uses vi and bash, here’s the secret…

Create ~/.inputrc

set meta-flag on
set input-meta on
set output-meta on
set convert-meta off

add this to your .bashrc

set -o vi

Thanks Adam!

Posted in code | Tagged , | Leave a comment

moving from svn to git

I’ve been learning git lately and it seems much easier to use than subversion for branching and merging, but I still have yet to become adept at looking at a file history. It seems to be the way that a lot of projects are moving, especially for rails and open source projects; besides, all the kids are doing it, so I figured I would follow the trend. In addition to using it pretty simply for small projects, I’m moving a project from subversion to git, which turn out to be a little bumpy, so I thought I would share.

I started with these awesomely simple instructions to cleanly migrate your subversion repository with the addition of a handy script to automatically create an svn.authors file.

This all seemed to go well, until we tried to run the code and learned that svn-git failed to fetch a directory! svn-git really ought to warn you somehow that it doesn’t support fetching externals. This I learned by noticing that the svn log had no checkins of those files and then saw when I did a clean svn checkout that it was fetching externals for the vendor/plugins directory. Of course that makes a lot of sense, but I didn’t set up the svn so I didn’t know. Then I spent some time wandering through the wilderness of blogs and mailing lists learning about svn externals and git submodules, and I found some interesting clues:

After all of that, I stepped back and thought about what I actually needed for this project. We’re currently at 2.0.2 and planning to upgrade to the the latest, and it turns out that all of the plugins that we’re currently tracking on subversion have moved their latest versions to git. So, I decided to just pull in the vendor/plugins directory verbatim, detaching the external reference, and move to git submodules as we upgrade. What I really wanted to do, but didn’t see how to, was to reference the plugin code as an http URL and keep as a submodule, so that I would have a handy reference to source location and revision.

$mkdir project-tmp
$cd project-tmp/
$git-svn init svn://myserver/project/trunk
$git config svn.authorsfile ../svn-users.txt
$git-svn fetch
    :
Checked out HEAD:
  svn://myserver/project/trunk r999

$cd vendor
$svn co svn://whatever.com/myproject/trunk/vendor/plugins
$cd plugins
$rm -rf .svn
$git add .

$cd ..
$git clone project-tmp project
$rm -rf project-tmp
Posted in code | Leave a comment

generating an .htaccess file for wordpress migration

So, I’ve been working to migrate my ultrasaurus weblog from Movable Type to WordPress (this one will come later). Since all the links were changing anyhow, I decided to move from ugly numbered permalinks to pretty links based on the title of the post. I only had a few hundred posts, but enough so I didn’t want to be doing it by hand. Since I’m learning Ruby and infatuated with it at the moment, I wrote a Ruby script to generate the .htaccess directives.

In case this would be helpful to anyone else, here’s the code:


require 'date'
require 'find'

Find.find('./archives/') do |fname|
# puts fname
date_string = ""
title = ""
next if File.directory?(fname)
File.open(fname, "r") do |f|
    f.each_line do |line|
        if m =  line.match("(<h2 class=\"date\">)(.*)(</h2>)") then
            date_string = m.captures[1]
        elsif m = line.match("(<h3 class=\"title\">)(.*)(</h3)") then
            title = m.captures[1].downcase
        end
    end
end

# for some reason my mt archives include some old drafts with no titles
next if title == ""

oldfilename = File.basename(fname)

# 1) remove chars that I think wordpress removes
# 2) change spaces to dashes
# 3) handle this case to avoid ---
#       Emmy Award for Outstanding Lead Actress - Miniseries or Movie
#    also avoid -- which I saw in my data, but not sure why it was there
# 4) remove trailing dash if there is one
#  Thank you ruby-talk http://www.ruby-forum.com/topic/167299
title = title.gsub(/[(,?!\'":\.+=\/)]/, '').gsub(' ', '-').gsub('--','-').gsub(/-$/, '')

# get the new path to the entry, like "/2003/03/brand-new-weblog/"
date = Date.parse(date_string)
newpath = sprintf("%d/%02d/%s/", date.year.to_s, date.month.to_s, title);

# we want something like this:
# redirect 301 /old/old.htm http://www.you.com/new.htm

output = "redirect 301 /sarahblog/archives/" + oldfilename + " http://www.ultrasaurus.com/sarahblog/" + newpath
puts output

end # loop thru files in directory
Posted in code | Leave a comment

Scaffolds != Rails

In pretty much every blog tutorial generate scaffold plays a central role; however, the rails guides don’t say much about scaffolding. I wasn’t sure where to go next in my development, as I asked in my last post: “Adding attributes and other models: do I scaffold again or just write code?”

I’ve spent some time reading about scaffolding on the Rails lists, and have saved some enlightening posts from various folks. Most of the interesting discussion took place just a few months after the introduction of Rails 2 when the generated scaffold code apparently underwent significant changes to become more REST-like and the dynamic scaffold command was removed from the core of Rails (but is still available as a plugin).

What was dynamic scaffolding?

> 1) In a controller class to bind controller to its respective model as in
> class ContactController < ApplicationController
> scaffold contact # contact here is the name of the model called
> contact
> end

This style of scaffolding has been removed from Rails 2.0. It used to be referred to as dynamic scaffolding, but it didn’t really help people learn about Rails or give them a way to modify the generated interface, so we killed it.
– nice response by DHH to a new Rails developer

Many of the Rails folks are clearly not fans of scaffolding at all and some argue that it is at best good marketing and at worst causes people to become rigid in their use of Rails. Rails is “opinionated,” but it is also designed to be flexible.

What is Scaffolding?

Scaffolds != Rails

They’re a starting point, and as such just give you something to start with. Scaffolds aren’t meant to be your whole application, so the code is treated just like code that’s written independent of them: If your object model changes, then you need to change your views and controller logic to match. – Jeremy McAnally

Just look at the generator as a secretary who can type all the “vanilla” code for you, then edit the migration to add the specifics… I need longtext for my notes fields, but the scaffold just uses text… so I always edit the migrations after they’re generated.

But listing your fields on the generate command does get those fields auto-populated into the views, letting the “secretary” do more of your typing for you.– Ar Chron

it does what the name implies (”scaffold”, remember?), which is A Good Thing. In other news, the “preferred way of working” is still, after all those years, to actually writing code while knowing wtf is going on. — Johannes Holzer

What is Bad about Scaffolding

…scaffolding really is such an insignificant part of Rails that its flaws should have no bearing on your decision of whether or not to use Rails. Rails isn’t a visual toolkit, it’s a serious development framework. You just have to make it over two humps in the learning curve: the Rails API hump and then later the Dynamic Ruby hump and you’ll be golden. — dasil003

my biggest problem with the new scaffolding is that it reinforces the notion that a “resource” is a controller/model stack. That, in turn, means that it discourages recognition of those cases where a resource might involve something other than a one-to-one
correspondence between a controller and a model.

In REST, there’s nothing about the concept of “resource” that implies database persistence, or persistence at all for that matter. Of course, Rails is a database-centered technology, not an all-purpose embodiment of every nuance of “resource”. Still, I think the
scaffolding presents too monogamous a picture of controller/model relations, if I may put it that way. The result is that people worry that if they do something in one controller that involves two models, they’ve done something “unRESTful”. That’s a red herring. — David A. Black

I was confused about it; Roy Fielding (I think it was) explained it like this: a resource is like your P. O. Box; you know where it is; it never changes; and the postal workers know where it is, it never changes. But, what you’ll find in there? Whatever the postal workers
think is appropriate. The analogy is imperfect, because you can’t do content negotiation at your P.O.Box. Imagine if you could say, “I only want first-class mail, please, no bulk mailings, English versions if available” and then the analogy is pretty good, I think.

My very first ReST Web Service was written in Python, and serves geographic conversions for Northern Ohio. (GeoGeeks: available at http://uber.engineer.co.summit.oh.us/ws/spc3401/ ) There’s no real reason to expect anyone to request any given resource more than once, so it’s not a database, it’s just a calculation. It’s not very browser oriented. It also doesn’t do CRUD — just “R.” If I’d learned Rails 2.0 scaffolding first, I might have had even more “unlearning” to do
before I got straightened around.

Rails 2.0 is “ReSTish” and that’s good, but it’s still browserfied. The adaptation of ReST to the browser by Rails is very, very clever, but perhaps a little distracting. Interested people might look at http://pragdave.pragprog.com/pragdave/2007/03/the_radar_archi.html for an example of why providing a ReST Web Service shouldn’t be conflated (mentally) with manipulating it via the browser. — Ron Phillips

> However, as far as I could tell, Rails now makes it really hard to

> deviate from RESTful approach, and that forces me, the newbie, to

> stick to it.

This just described why I think scaffolding is bad. It indirectly forces newcomers to do things a specific way. If you use the scaffolding, you start building controllers based off the code there. If you learned to create a controller and views without the scaffolding, you’d be more free to do things as you see fit.– Branko

Scaffold should not Substitute for Documentation

Railes substitues proper “getting started” documentation for scaffolded
code generation which makes it really tough on newcomers. People who’ve
been doing Rails as long as I have don’t really care because we don’t use scaffolding. However, I work with newbies all the time and it’s much easier to start them on Rails 1.x and move to Rails 2.0 and REST later. The original scaffold generator was very good for explaining how controllers work with models and views. link_to used a hash and not a named route. Named routes are cool, but they are confusing to a newbie. Same with
respond_to.

The only upshot for Rails 2.0 scaffolding is that it’s much more production-ready. — Brian Hogan

In training people in Rails, I definitely do not start with REST and resources. map.resources is essentially a macro that creates a bunch of named routes for you — so if you don’t know what a named route is, you can only do it in a black-box and parrot-like way. Learning named routes doesn’t make much sense until you understand routes, and routes don’t make sense until you know the basics of the request cycle… and so forth. So I would never introduce someone to Rails by telling them to write map.resources in routes.rb and trying to proceed from there. — David A. Black

Scaffold == Marketing

I think part of the problem is that “scaffolding” should not be part of any Rails developer’s vocabulary. Scaffolding is too limiting and “opinionated” to be useful in 99% of real-world applications. Not to mention all the RESTful issues that David A. Black has already
mentioned. You can’t really be RESTful AND be scaffolding.

In my humble opinion, “scaffolding” is the marketing tool to convince people to check Rails out. I know it worked on me a few years back. But, for most, it will quickly become forgotten. –Fred

Scaffold has its Place

Philosophically, the name scaffold was chosen early on to suggest a temporary structure upon which you can lean as you start building but one which you intend to take down as the main structure begins to sustain itself. In that regard the 2.x implementation is more sound philosophically: the scaffold exists in the early stages of development in a way that will always go away over time. — AndyV

Posted in code | 4 Comments

rails 2 day 4: rcov and more behavior-driven development

Today, we’ll follow modified steps, as recommended by Matt Wynne who suggested refactoring to remove duplication as an extremely important step:

  1. Describe a feature
  2. Execute the feature and Watch it fail
  3. Write the code to make it pass
  4. Refactor
  5. Go to step 2

Also, since we’re using the generate scaffold command, we should remove unused code when refactoring as suggested in the original Four Days on Rails tutorial. I’ll also be using RCov to look at how much the feature description covers the code. I think this is a helpful way of digging into what the scaffold command actually did. This tutorial picks up where day 3 finished. You can skip day 1 or 2, if you already have installed Ruby on Rails and know a little bit about it.

Today we will:

  1. Install RCov
  2. Look at Code Coverage
  3. Write more scenarios
    1. Create
    2. Edit
    3. Delete
  4. Refactor to remove duplication
  5. Review what we learned

 


 


Install RCov

Elaborating slightly on the nice instructions on the cucumber wiki, Aslak recommends that you use spicycode’s RCov instead of the ‘official’ one, “as it currently segfaults too much for most people’s taste.”

gem sources -a http://gems.github.com
gem uninstall rcov
gem install spicycode-rcov

Second, you’ll need to open up the cucumber generated task file and set the rcov config option (add one line in bold).

in todolist/lib/tasks/cucumber.rake


$:.unshift(RAILS_ROOT + '/vendor/plugins/cucumber/lib')

require 'cucumber/rake/task'

Cucumber::Rake::Task.new(:features) do |t|

  t.cucumber_opts = "--format pretty"

  t.rcov = true

end

task :features => 'db:test:prepare'


Look at Code Coverage

Now when you run:

rake features

And you point your browser at: http://localhost/todolist/coverage/

You’ll see:

We can see that we don’t have complete coverage in two files: webrat.rb and tasks_controller.rb The first doesn’t matter, since it is part of the test framework (in fact there ought to be some way to exclude that), but we need to be concerned that half of our generated controller code is untested. By clicking on the filename, we can see the detailed coverage where the lines of code that are not covered are highlighted in red:

It is unsurprising that we’re covering just 40% of this file, since we’ve written just a single of scenario so far.


More Scenarios

Let’s look at what isn’t getting covered.

  • show
  • new
  • edit
  • update (called from edit)
  • destroy
  • create (called from new)


Create

To create a task, we can leverage quite a bit of webrat, plus a step we wrote before. Add the following scenario to the feature file:

in features/tasklist.feature

Scenario: Add a Task
When I go to the tasks page
When I follow "New task"
When I fill in "description" with "go shopping"
And I press "Create"
Then I should see "Task was successfully created."
And I should see "go shopping"

then run

rake features

You’ll see that all of the new steps that I just wrote for the “add a Task” scenario magically worked. What just happened? You can see from the output of “rake features” that the first step was already defined in tasklist_steps.rb (see day 3), but each of the others is defined in webrat_steps.rb. With a little practice you’ll learn the webrat lingo, and it’ll save you a bunch of time. Pretty cool, huh?

Now if we go back to look at our code coverage (http://localhost/todolist/coverage/), the tasks_controller.rb coverage is at 64.7%.

Clicking on the file, we can see the lines of code that are now tested. We’ve covered new and half of create. (Not quite sure what would cause that error condition, but we’ll move on for now.)


Edit

Now we’ll do some behavior-driven development, since the auto-generated task list and edit workflow isn’t exactly what I wanted. This is what I see after adding the “go shopping” task manually:

I don’t really need the “show” link (since my task only has its description as data and that’s shown in the list and since I’m removing that, I can just make the description itself as a link. So I want to add two scenarios to support my intended edit behavior:

  • Clicking on the description link allows edit
  • After Editing I return to the task list
Scenario: Clicking on description link allows edit
Given that I have created a task "go shopping"
When I go to the tasks page
When I follow "Go Shopping"
Then I should see "Editing Task"

As expected, the new scenario fails. Time to write the code! The list of tasks can be found in app/views/tasks/index.html.erb

As you can see that I’ve modified line 10 to link the description to the edit task page. Note that (h task.description) needs to be enclosed in parens. We want to keep the h, just to make sure that the description is properly escaped, in case it has special characters like ‘<'. I also removed show and edit links. Now, when I run 'rake features' all of my steps pass. Yay!

But wait! I still have the “show” method in my controller. What’s up with that? If I look at my coverage report, it shows that it is being called. In my controller, both create and update redirect to @task (which is the “show” page), like I did in day 2, I’ll modify those to redirect to index instead.

in app/controllers/task_controller.rb

change:

format.html { redirect_to(@task) }

to:

format.html { redirect_to :action => "index" }

and remove the show method

Rerun ‘rake features’ just to make sure all is good. And you can now see that the tasks_controller code coverage is at 62%. We’re calling edit, but not yet update… on to the next scenario.

Scenario: After Editing I return to the task list
Given that I have created a task "go shopping"
When I go to the tasks page
When I follow "Go Shopping"
And I fill in "description" with "buy bagels"
And I press "Update"
Then I should see "Task was successfully updated."
And I should see "Listing tasks"
And I should see "buy bagels"

When I run “rake features” the scenario passes. (Yay!) I don’t know how to hit the error condition in update either, but I’ll leave that for another day.


Delete

I left delete for last since it is a bit trickier. With the design of the app, there is a “destroy” link for each task in the list, so I have to figure out which one to click.

I found this handy step definition in an example by Aslak:

When /^I delete the (\d+)(?:st|nd|rd|th) lorry$/ do |pos|
visit lorries_url
within("table > tr:nth-child(#{pos.to_i+1})") do
click_link "Destroy"
end
end

When I first looked at that I thought > tr:nth-child was some wild new Ruby syntax, but the kind folk on the RSpec list answered my question by pointing me to the CSS selector doc. I had forgotten that > was a CSS selector since I had never actually used that selector before. That hint combined with a previous thread and some digging around to brush up my Ruby and Rail skills led me to a solution. Here is my scenario for delete:

Scenario: Delete a Task
Given that I have created a task "task 1"
When I go to the tasks page
And I click "delete" for "task 1"
Then I should see "Listing tasks"
And I should not see "task 1"

To make this work, I can define a unique DOM id for each of my table row, then I can find the id for “task 1″ and then click the link inside that table row.

1) Define a unique DOM id for each table row

In app/views/tasks/index.html.erb, we have some Ruby code which iterates through the list of tasks (@tasks) and for each ‘task’ there is a table row. To add a unique id for the table row, I insert a snippet of ruby code within <% … %> which evaluates to a unique string. In this case I use the string “task” plus to id of the task itself, generating task4, task5 or whatever.


<% for task in @tasks %>

  <tr id="<%="task"+task.id.to_s%>">

2) Find the id for “task 1″

Given the description of a task, I need to find its id. In the ActiveRecord::Base API docs, it describes some handy syntax for finding by attribute value. “Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by appending the name of an attribute to find_by_, find_last_by_, or find_all_by_.” Since the attribute I have is “description,” I can call

task = Task.find_by_description(desc)

to get the task object where the description attribute matches the given parameter.

3) Click the link inside the table row

Putting it all together I can create a step definition like this:

When /^I click "delete" for "(.*)"$/ do |desc|
task = Task.find_by_description(desc)
within("table > tr#task"+task.id.to_s) do
click_link "Destroy"
end
end

I run “rake features” and all is good. The only thing left to do is to rename the “Destroy” link to be “delete” as I described it and fix up the step to have a more general definition:

When /^I click "(.*)" for "(.*)"$/ do |link, desc|
task = Task.find_by_description(desc)
within("table > tr#task"+task.id.to_s) do
click_link link
end
end

I run “rake features” and see that 26 steps passed. Woo hoo! Code coverage shows 83.8% of the controller file (everything but those pesky error conditions.)


Refactor to Remove Duplication

Now that the feature description roughly covers the functionality of our app, I sought to take Matt’s advice and look at the code and see if we need to remove some duplication.
I looked first at the controller and found something odd:

in app/controllers/tasks_controllers.rb:

class TasksController < ApplicationController
# GET /tasks
# GET /tasks.xml
def index
@tasks = Task.find(:all)

respond_to do |format|
format.html # index.html.erb
format.xml  { render :xml => @tasks }
end
end

# GET /tasks/new
# GET /tasks/new.xml
def new
@task = Task.new

respond_to do |format|
format.html # new.html.erb
format.xml  { render :xml => @task }
end
end

# GET /tasks/1/edit
def edit
@task = Task.find(params[:id])
end

The index and new methods repeat code, but the edit method, which I would expect to contain the same repeated 4 lines omits the code. In fact, if I remove those lines in index and new, the app works fine.

class TasksController < ApplicationController
# GET /tasks
# GET /tasks.xml
def index
@tasks = Task.find(:all)
end

# GET /tasks/new
# GET /tasks/new.xml
def new
@task = Task.new
end

# GET /tasks/1/edit
def edit
@task = Task.find(params[:id])
end

When I run 'rake features' all the steps pass and poking at the application also yields success. What's going on? There must be something happening by default. At first I couldn't figure out where ApplicationController was defined, but an answer to my question on the Rails list pointed out that ApplicationController is one of the classes created by generate scaffold (defined in app/controllers/application.rb). Looking at the code (and comments) we can see that it simply sets some defaults for any controller in the application. ApplicationController is a subclass of ActionController::Base, which we can look up in the Rails API Doc. The doc explains that "Actions, by default, render a template in the app/views directory corresponding to the name of the controller and action after executing code in the action." I suppose the extra code is in there to facilitate modifying it, in case we wanted the action to do something special.


What did we learn?

Today we learned about:

  • installing and using RCov
  • cucumber steps that can be quickly defined using webrat
  • dynamic-attribute finders: find_by
  • adding a unique DOM id to more easily test the app

We also learned that you need to understand code in order to refactor it, but, of course, we already knew that :)

There ends day 4, but I still haven't completed all of the features of the Four Days on Rails tutorial. Topics yet to learn:

  • Adding attributes and other models: do I scaffold again or just write code?
  • Associated Models
  • Pagination
  • Updating multiple records
Posted in code | 4 Comments

rails 2 day 3: behavior-driven development

Now that we have learned some basic Ruby syntax and gained some understanding about what the Rails generate scaffold script does, it is high time we started using a more modern approach to coding. In fact, if you recall at the end of day 2, I realized with horror that we had actually modified code and added features without developing the tests first. This defied everything I had ever heard about good coding practices from the Ruby crowd and I set off to mend my ways.

Rick Denatale describes the process of test-driven/behavior-driven development as:

  1. Write the test/spec
  2. Ensure that it FAILS
  3. Write the code to make it pass
  4. Goto step 1

After reading a bit about test- and behavior-driven development, I decided to use a relatively new framework called cucumber which uses natural language to describe features.

Today we will:

  1. Install cucumber
  2. Set up the application
  3. Describe a feature
  4. Execute the feature and Watch it fail
  5. Write the code to make it pass
  6. Review what we learned

 


 


Install Cucumber

Based on these install instructions

sudo gem install rspec rspec-rails cucumber webrat

important: Cucumber 0.1.12 and up depends on Webrat 0.3.2.1 or higher, which as of this writing is not yet officially released to Rubyforge’s gem repository. In the meanwhile, install Bryan Helkamp’s snapshot gem:

gem sources -a http://gems.github.com
sudo gem install brynary-webrat

The plugins’ dependencies must be installed separately:

gem install term-ansicolor treetop diff-lcs nokogiri

 


Setup the Application

First we’ll create the Rails “to do list” application:

cd $webroot
rails -d mysql todolist
cd todolist
rake db:create:all
rake db:migrate

Now we’ll set up cucumber for the project

ruby script/generate cucumber
create  features/step_definitions
create  features/step_definitions/webrat_steps.rb
create  features/support
create  features/support/env.rb
exists  lib/tasks
create  lib/tasks/cucumber.rake
create  script/cucumber

Just to make sure that everything is installed correctly:

rake features

If that runs without errors you are ready to rock.

 


Describe a Feature

In the features directory that was auto-created for us with the cucumber script, we create a .feature file which starts with a description of the feature. The first section that describes the feature appears to be purely documentation; however the “scenario” sections will each become part of the executable feature definition. For starters we’ll do something simple.

features/tasklist.feature

Feature: Tasks
In order to keep track of tasks
People should be able to
Create a list of tasks

Scenario: List Tasks
Given that I have created a task "task 1"
When I go to the tasks page
Then I should see "task 1"

We know we haven’t written any executable steps, but we’ll execute it anyhow:

Note that one of the steps is already defined in webrat. Isn’t that cool? When we set up cucumber for the project, it automatically includes step_definitions/webrat_steps.rb which defines some common steps. As you get the hang of this, you reuse certain word patterns which map to specific tests. But we’re getting ahead of ourselves. We need to dive into the creation of “steps” which make up our executable spec. Cucumber gives a some handy snippets to get us started (in the output of “rake features” above). We’ll paste these into a new file that we’ll create in the “features/step_definitions” directory:

features/step_definitions/tasklist_steps.rb

Given /^that I have created a task "(.*)"$/ do |desc|
Task.create!(:description => desc)
end

When /^I go to the tasks page$/ do
visit "/tasks"
end

Note that I touched up the first step to include a regular expression. This means I could add Given that I have created a task "foo" to another scenario and it would match this step.


Short aside on task creation syntax

To create the task, I’m calling my Task model directly (since I’m new to Rails, I looked up the ActiveRecord::Base syntax in the Rails Framework API docs). In my first pass I wrote:

task = Task.new(:description => desc);
task.save

However, Aslak Hellesøy kindly pointed out that it would fail silently with that syntax, and instead I should call task.save! or the even simpler Task.create!(:description => desc). I had missed create! in the documentation, since it is part of ActiveRecord::Validations. The API doc is a little confusing on this point, but looking at the source shows that ActiveRecord::Validations is included as a module. Pat Maddox notes that he uses the bang version (.save!) in tests, and the non-bang version (.save) in production code since validation errors aren’t exceptional.


Back to Step 3

Looking in features/step_definitions/webrat_steps.rb, you can see the definition of our third step:

Then /^I should see "(.*)"$/ do |text|
response.body.should =~ /#{text}/m
end

Ok, now we have a simple spec. Is it time to write the code? No!


Execute the Feature and Watch it Fail


As expected, we see errors on our first step, since we have not yet written any code for the application.


Write the code to make it pass

Now, at last it is time to write code

$ ./script/generate scaffold Task description:string
$ rake db:migrate

Run the spec again..

It passes, yay!


What did we learn?

When we first set up our app, to setup cucumber:

ruby script/generate cucumber

To describe our feature, we create two files:

  • features/xxx.feature
  • features/step_definitions/xxx_steps.rb

To run the feature description:

rake features
Posted in code | 10 Comments

getting started with rails 2 – day 2

In Day 1 with Rails, we built a simple application that let us manage a list of categories using the powerful generate scaffold script. Today, we’ll look under the hood and learn about the code that was created for us, so that we can modify the application to do just what we want (or, rather, what the tutorial Four Days on Rails tutorial did, as I continue to update that tutorial for Rails 2.)

You’ll get the most out of Day 2, if you already know Ruby or you first read chapters 0-3 of the humble little Ruby book or some other introduction to the language. Or, of course, you can just wing it.

You also should know about the MVC (Model View Controller) design pattern. Although if you don’t know MVC already, you’ll get the hang of it soon, at least from the Rails perspective. The Getting Started Guide has a nice intro to MVC and elaborates on how Rails applies this venerated pattern:

2.1.1. Models A model represents the information (data) of the application and the rules to manipulate that data. In the case of Rails, models are primarily used for managing the rules of interaction with a corresponding database table. In most cases, one table in your database will correspond to one model in your application. The bulk of your application’s business logic will be concentrated in the models.

2.1.2. Views Views represent the user interface of your application. In Rails, views are often HTML files with embedded Ruby code that performs tasks related solely to the presentation of the data. Views handle the job of providing data to the web browser or other tool that is used to make requests from your application.

2.1.3. Controllers Controllers provide the “glue” between models and views. In Rails, controllers are responsible for processing the incoming requests from the web browser, interrogating the models for data, and passing that data on to the views for presentation.

In today’s tutorial, we will learn about:

  1. The Model
  2. The Controller
  3. Views
  4. Tailoring the Generated Scaffold Code
  5. Review what we learned

 


 


The Model

The definition of the model is in one of the files generated by scaffold:

app/models/category.rb
class Category < ActiveRecord::Base
end

This is a Ruby file that declare a class named Category that inherits from class ActiveRecord::Base. To define a class in Ruby, you place the class keyword at the beginning of a line, followed by the class name and a < and the class it inherits from.

Active Record is one of the "gems" installed with Rails. Looking in the Ruby on Rails api documentation for ActiveRecord::Base in the Classes section shows all of the methods, attributes, exceptions and other parts available in class ActiveRecord::Base.

An instance of the class Category could be called anything but the Rails convention is to use a variable named category or @category. The :: symbol is the Ruby scope operator. In ActiveRecord::Base it means that you are referring to the Base of ActiveRecord and not some other base.

note: I've adapted this nice explanation from Fairleads along with language note from the humble little ruby book)

We will customize our Model by adding code here.


Validation

Let's say we want to make it so that each category appears once and only once in the category list. If you try that now, you'll notice that the application allows a duplicate entry. Go ahead and delete the duplicate. We'll make sure it isn't allowed in the future, by adding validation to the model.

Rails gives you a lot of error handling for free (almost). To demonstrate this, add some validation rules to the empty category model:

app/models/category.rb

class Category < ActiveRecord::Base
validates_length_of :title, :within => 1..20
validates_uniqueness_of :title, :message => "already exists"
end

These entries will give automatic checking that:

  • validates_length_of: the field is not blank and not too long
  • validates_uniqueness_of: duplicate values are trapped. I don't like the default Rails error message - 'xxx has already been taken' - so I provide my own. Note: This is a general feature of Rails - try the defaults first; if you don't like anything, overwrite it.

Documentation: ActiveRecord::Validations::ClassMethods

To try this out, now try to insert a duplicate record. This time, Rails will you prevent you from creating a duplicate record (see below). The style is a bit in your face -- it's not the most subtle of user interfaces. However, what do you expect for free?


The Controller

Let's look at the code behind the controller. The controller is where the programming logic for the application
lies. It interacts with the user using views, and with the database through models. You should be able to read the
controller and see how the application hangs together.

Some methods of the controller along with the class definition produced by the scaffold script are listed below:

app/controllers/categories_controller.rb

class CategoriesController < ApplicationController
# GET /categories
# GET /categories.xml
def index
   @categories = Category.find(:all)

   respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @categories }
   end
end

# GET /categories/1
# GET /categories/1.xml
def show
   @category = Category.find(params[:id])

   respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @category }
   end
end
:
:
# DELETE /categories/1
# DELETE /categories/1.xml
def destroy
   @category = Category.find(params[:id])
   @category.destroy

   respond_to do |format|
      format.html { redirect_to(categories_url) }
      format.xml  { head :ok }
   end
end
end

Note that just like the model, the controller is simply a ruby class file. Each method in the class defines an action. Actions, by default, render a template in the app/views directory corresponding to the name of the controller and action after executing code in the action. For example, the index action in our Categories controller renders a list of categories; however, note that unlike index, the destroy action will not render a template. After performing its main purpose (calling destroy on the category object that the user selected), it initiates a redirect instead.

Note: there is quite a bit of Ruby magic going on in the generated controller file with exactly how the respond_to block works. Perhaps I'll dive into that once I've got the basics down.


Views

Views are where the user interface is defined. Rails can render the final HTML page presented to the user from three components:

  • Layout. A layout provides common code used by all actions, typically the start and end of the HTML sent to the
    browser.
  • Template A Template provides code specific to an action, e.g. 'List' code, 'Edit' code, etc.
  • Partial A Partial provides common code which can be used in used in multiple actions.

If you look at the view files generated by the scaffold command, you will see that they are .erb files. I'm not sure what 'erb' stands for, but they have replaced .rhtml files in previous versions of Rails. These files are a mix of html markup with snippets of ruby code in them.

  • app/views/
    • categories/

      • index.html.erb
      • show.html.erb
      • new.html.erb
      • edit.html.erb
    • layouts/
      • categories.html.erb


Layout

Rails Naming conventions: if there is a template in app\views\layouts\ with the same name as the current controller then it will be automatically set as that controller's layout unless explicitly told otherwise.


apps/layouts/categories.html.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
   <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
   <title>Categories: <%= controller.action_name %></title>
   <%= stylesheet_link_tag 'scaffold' %>
</head>
<body>

<p style="color: green"><%= flash[:notice] %></p>

<%= yield %>

</body>
</html>

This is mostly HTML, plus a few bits of Ruby code embedded within <% %> tags. This layout will be called by
the rendering process regardless of the action being run. It contains the standard HTML tags - the
<html><head>...</head><body>...</body></html> that will appear on every page.

The Ruby bits in bold are translated into HTML during the Rails rendering process as follows:

  • action_name is an ActionController method which returns the name of the action the controller is processing (e.g. 'Edit') - this puts an appropriate title on the page, depending on the action being run.
    Documentation: ActionController::Base
  • stylesheet_link_tag is a Rails helper - a lazy way of generating code. There are a lot of these 'helpers' within Rails. This one simply generates the following HTML: <link href="/stylesheets/scaffold.css" media="screen" rel="Stylesheet" type="text/css" />
    Documentation: ActionView::Helpers::AssetTagHelper
  • flash Rails provides a technique for passing 'flash' messages back to the user - e.g. an 'Update Successful' message which displays on the next screen and then disappears. These can be picked up easily when included in the layout (adding it to the Layout means it will appear on any screen). (The flash message will, of course, only appear when the previous screen sends such a message.
    Documentation: ActionController::Flash
  • yield is the key to what happens next. It allows a single standard layout to have dynamic content inserted at rendering time based on the action being performed (e.g. 'edit', 'new', 'list'). In Ruby the yield command will execute a block of code that is passed as an argument. In this case, the code will insert dynamic content from a Template with the same name - see below.

    Documentation: see Ruby language docs.


Templates

Rails naming convention: templates are held in app\views\'controller'\'action'.erb.html. The basic list action is perhaps easiest to understand. This is the default action for the controller and is therefore the 'index' template


app/views/categories/index.erb.html

<h1>Listing categories</h1>

<table>

   <tr>

      <th>Title</th>

   </tr>

<% for category in @categories %>

   <tr>

      <td><%=h category.title %></td>

      <td><%= link_to 'Show', category %></td>

      <td><%= link_to 'Edit', edit_category_path(category) %></td>

   <td><%= link_to 'Destroy', category, :confirm => 'Are you sure?', :method => :delete %></td>

</tr>

<% end %>

</table>

<br />

<%= link_to 'New category', new_category_path %>

Below are some notes about the more interesting bits of code highlighted (bold) above

  • for ... in ... end This is some simple Ruby code to loop through the items in the array @categories. The enclosed table rows are rendered for each category in the list.
  • h automatically 'escapes' HTML code. One of the problems with allowing users to input data which is then displayed on the screen is that they could accidentally (or maliciously) type in code which could break the system when it was displayed. For example, think what would happen if a user typed in </table> as a Category. To guard against this, it is good practice to 'HTML escape' any data which has been provided by users. This means that e.g. </table> is rendered as &lt;/table&gt; which is harmless. Rails makes this really simple - just add an 'h' as shown
  • confirm is a useful optional parameter for the link_to helper -- it generates a Javascript pop-up box which forces the user to confirm the Destroy before actioning the link.
  • link_to simply creates a link -- the most fundamental part of HTML... <a href="/categories/2">Show</a>
    Documentation: ActionView::Helpers::UrlHelper

The 'new' action template created by the scaffold script is given below:

app/views/categories/new.erb.html

<h1>New category</h1>

<% form_for(@category) do |f| %>

  <%= f.error_messages %>

  <p>

    <%= f.label :title %><br />

    <%= f.text_field :title %>

  </p>

  <p>

    <%= f.submit "Create" %>

  </p>

<% end %>

<%= link_to 'Back', categories_path %>

form_for is part of the Rails FormHelper class. The 'new' form is defined with the block of Ruby code between do and end. Form helpers are designed to make working with models much easier compared to using just standard HTML elements by providing a set of methods for creating forms based on your models. This helper generates the HTML for forms, providing a method for each sort of input (e.g., text, password, select, and so on). When the form is submitted, the form inputs will be bundled into the params object and passed back to the controller. The form that is generated can be seen here:


<form action="/categories" class="new_category" id="new_category" method="post"><div style="margin:0;padding:0">

 <p>

 <label for="category_title">Title</label><br />

 <input id="category_title" name="category[title]" size="30" type="text" />

 </p>

 <p>

 <input id="category_submit" name="commit" type="submit" value="Create" />

 </p>

</form>

Documentation: ActionView::Helpers::FormHelper


Tailoring the Generated Scaffold Code

The code generated by the Scaffold script is perfectly usable 'out of the box', and is robust once you have added enough validation into your data model. However, if that's all there was to developing Rails applications, then all the Rails apps would be boring. Now that we understand a little bit of what's going on, we can start to tailor the application to do exactly what we want.


Modifying the Controller

In a list view, as we can see on the mail page, I would expect the records to be displayed in alphabetical order. This requires a minor change to
the controller:

app\controllers\categories_controller.rb (excerpt)

# GET /categories

  # GET /categories.xml

  def index

    @categories = Category.find(:all, :order=>'title')

    respond_to do |format|

      format.html # index.html.erb

      format.xml  { render :xml => @categories }

    end

  end

Remember that Category is an ActiveRecord, so you can look up the find method on ActiveRecord::Base and see all the nifty options.

Documentation: ActiveRecord::Base.find

In this application, the show screen is unnecessary - all the fields fit comfortably on a single row on the screen.
So, def show can disappear, and let's go straight back to the list screen (categories index) after an 'Edit':


(excerpt)

(excerpt)

 # POST /categories

  # POST /categories.xml

  def create

    @category = Category.new(params[:category])

    respond_to do |format|

      if @category.save

        flash[:notice] = 'Category was successfully created.'

        format.html { redirect_to :action => "index"  }

        format.xml  { render :xml => @category, :status => :created, :location => @category }

      else

        format.html { render :action => "new" }

        format.xml  { render :xml => @category.errors, :status => :unprocessable_entity }

      end

    end

  end

  # PUT /categories/1

  # PUT /categories/1.xml

  def update

    @category = Category.find(params[:id])

    respond_to do |format|

      if @category.update_attributes(params[:category])

        flash[:notice] = 'Category was successfully updated.'

        format.html { redirect_to :action => "index" }

        format.xml  { head :ok }

      else

        format.html { render :action => "edit" }

        format.xml  { render :xml => @category.errors, :status => :unprocessable_entity }

      end

    end

  end

The flash message will be picked up and displayed on the next screen to be displayed - in this case, the list screen.


Sharing Variables between the Template and Layout

Below you can see that I've moved the <h1>...</h1> heading text out of the Template into the Layout so that we can keep the formatting consitent across pages. As each template will have a different heading, I need to set the value of the variable @heading in the Template. Rails is quite ok with this - Template variables are available to Layouts at rendering
time.


app\views\layouts\categories.html.erb (exceprt)

<head>

  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />

  <title>Categories: <%= controller.action_name %></title>

  <%= stylesheet_link_tag 'scaffold' %>

</head>

<body>

<h1><%=@heading %></h1>

...


app/views/categories/index.html.erb (excerpt)

<% @heading = "Categories" %>

       

<table>

  <tr>

    <th>Title</th>

  </tr>

 

<% for category in @categories %>

  <tr>

    <td><%=h category.title %></td>

    <td><%= category["created_at"].strftime("%I:%M %p %d-%b-%y") %></td>    

    <td><%= category["updated_at"].strftime("%I:%M %p %d-%b-%y") %></td>

    <td><%= link_to 'Edit', edit_category_path(category) %></td>

    <td><%= link_to 'Destroy', category, :confirm => 'Are you sure?', :method => :delete %></td>

  </tr>

<% end %>

</table>

Since we removed the 'show' action above, I've also removed the link in the categories list view. Then I added created_at and updated_at, which if you recall from Day 1, were auto-generated for us as part of the scaffold.

Instead of the default date format (e.g. Sat Dec 13 23:26:19 UTC 2008), we're using a Ruby method strftime() to format the date and time fields (e.g. 11:26 PM 13-Dec-08)

Ruby Documentation: class Time


Partial Templates

You may have noticed that edit and new are almost idential. The scaffold does not assume that will be your design, so it doesn't prematurely optimize; however, in this app the new and edit pages share almost all of the same elements. Rails can allow these templates to share code by using a "partial" template. Create a new file called _category (all partial templates begin with an '_' per Rails convention) and insert the shared code:


app/views/categories/_category.html.erb

<% form_for(@category) do |f| %>

  <%= f.error_messages %>

  <p>

    <%= f.label :title %><br />

    <%= f.text_field :title %>

  </p>

  <p>

    <%= f.submit button_name %>

  </p>

<% end %>

<%= link_to 'Back', categories_path %>

This makes the edit and new templates very short and sweet. Note the use of the variable button_name, which you can see in action below.


app/views/categories/edit.html.erb (that's the whole thing!)

<% @heading = "Edit Category" %>

<%= render :partial => @category,

  :locals => { :button_name => "Update"} %>


app/views/categories/new.html.erb

<% @heading = "New Category" %>

<%= render :partial => @category,

  :locals => { :button_name => "Create"} %>

Now we have a nicely modular webapp following the DRY principle without that unsightly repeated code. We also understand much of the code that defines our little app.


What did we learn?

We learned about the following files that were created by the generate scaffold script:

  • app/models/category.rb
  • app/controllers/categories_controller.rb
  • app/view/layouts/categories.html.erb
  • app/view/categories/
    • index.html.erb
    • show.html.erb
    • edit.html.erb
    • new.html.erb

We also learned how to create a partial template: _category.html.erb.

I learned more of the Ruby language and how to navigate the Ruby API docs, and I hope you did too. This tutorial got a bit long and required quite a bit of changes from the old one. Please comment if you find any errors and I'll fix up up for posterity.

Notably absent from this tutorial has been the famous unit testing that I hear all good Ruby developers swear by. Perhaps I'll need to go offscript and read up on that for Day 3.

Stay tuned.

Posted in code | 1 Comment

getting started with rails 2 – day 1

The Getting Started Guide introduces several guiding principles from the Rails philosophy:

  • DRY – “Don’t Repeat Yourself” – suggests that writing the same code over and over again is a bad thing.
  • Convention Over Configuration – means that Rails makes assumptions about what you want to do and how you’re going to do it, rather than letting you tweak every little thing through endless configuration files.
  • REST is the best pattern for web applications – organizing your application around resources and standard HTTP verbs is the fastest way to go.

Aside from that very nice guide, there seem to be few tutorials for the newbie that are in Rails 2. I really like the approach I see in Four Days on Rails, so I’ve decided to see if I can replicate that tutorials in the latest version of Rails. I got through the first day in 3.5 hours and then spent another couple of hours reading up on what I had learned. Since it is hard for me to find contiguous stretches of time and other newbies may benefit from my experience, I’ve decided to document the process.

Sources:

My intent is not to plagiarize, but rather to give back to a most excellent community — the tutorial content is directly from Rails4Days. I quote Fabio Akita and Sean Lynch regularly and will give credit as I go.

In today’s tutorial, we will:

  1. Set up the environment
  2. Create the application
  3. Create the database
  4. Generate Scaffold
  5. Review what we learned (or how to do it next time in 5 mins)

 


 

Set up the environment

I’ve already got Apache installed on my Mac (see nice O’Reilly article). I didn’t actually use apache on the first day, but it just seems like a good idea to be working in my webroot and it was fun to actually find the webserver pre-installed on my new Mac.

For convenience, I defined webroot in my .bashrc:

webroot=/Library/WebServer/Documents

The first thing you have to do is update your gems:

sudo gem install rails --include-dependencies

You may probably need to update RubyGems as well:

sudo gem update --system

There’s a little trick to working with MySql (via wonko ) First, download and install MySQL for Mac OS X 10.5 (x86). Don’t install the x86_64 build or Ruby will refuse to speak to it. If you’ve already installed the x86_64 build, backup your databases,
install the x86 build on top of it, and restore your databases.

Once you’ve got the correct build of MySQL installed, pop open a terminal and run the following to install the MySQL/Ruby gem:

sudo env ARCHFLAGS="-arch i386" gem install mysql -- \
--with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib \
--with-mysql-include=/usr/local/mysql/include

Now that the setup is compete, onward to creating the app…


Create the application


cd $webroot

rails -d mysql todo

This creates an overwhelming number of files. You’ll soon see that Rails does this a lot, but the trick is to understand what’s going on as you use the shortcuts. The tutorial dives into these directories one by one, but for those of you who like an overview, the Getting Started Guide has a nice overview of the directory structure. If you are more of a bottoms-up learner, just skip the table and read on.

File/Folder Purpose
README This is a brief instruction manual for your application. Use it to tell others what your application does, how to set it up, and so on.
Rakefile This file contains batch jobs that can be run from the terminal.
app/ Contains the controllers, models, and views for your application. You’ll focus on this folder for the remainder of this guide.

config/

Configure your application’s runtime rules, routes, database, and more.
db/

Shows your current database schema, as well as the database migrations. You’ll learn about migrations shortly.
doc/ In-depth documentation for your application.
lib/

Extended modules for your application (not covered in this guide).

log/ Application log files.
public/ The only folder seen to the world as-is. This is where your images, javascript, stylesheets (CSS), and other static files go.
script/ Scripts provided by Rails to do recurring tasks, such as benchmarking, plugin installation, and starting the console or the web server.
test/ Unit tests, fixtures, and other test apparatus. These are covered in ../testing_rails_applications.html“>Testing Rails Applications
tmp/ Temporary files
vendor/ A place for third-party code. In a typical Rails application, this includes Ruby Gems, the Rails source code (if you install it into your project) and plugins containing additional prepackaged functionality.

 


Create Your Database

Next we’ll create a database. If you look at config/database.yml, you’ll see that separate environments of dev, test, and production may be defined. Because you specified -d mysql when creating the todo app the database settings are all of MySql. Neat, huh?

development:
adapter: mysql
encoding: utf8
database: todo_development
pool: 5
username: root
password:
host: localhost

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
adapter: mysql
encoding: utf8
database: todo_test
pool: 5
username: root
password:
host: localhost

production:
adapter: mysql
encoding: utf8
database: todo_production
pool: 5
username: root
password:
host: localhost

Notice the repeated text? Rails spells it all out for you to make it easy to modify for three separate environments. If you’ve got them all in one place, you can follow the DRY principle with this handy Rails shortcut.

defaults: &defaults
adapter: mysql
encoding: utf8
username: root
password:

development:
database: todo_development
<<: *defaults

test:
database: todo_test
<<: *defaults

production:
database: todo_production
<<: *defaults

we can set a bunch of defaults at the top, then specify what is different about our dev, test and production environments.

Akita notes: Notice that now you have a 'encoding' options that's set to UTF8 by default. The Rails app itself loads up with KCODE
= true by default as well, meaning that it silently starts with Unicode support already, which is great. But that 'encoding' configuration has
a new usage as well: everytime Rails connects to the database it will tell it to use this 'encoding' setting. Like issuing a 'SET NAMES UTF8'.

Rails 2 has far better database support. In the older versions, we'd have to actually type SQL commands and manually create the database. The procrastinating programmer who is only now learning Rails scores!

To create the database, simply type:

rake db:create:all

Note: MySql has to be started for it to work. If you get errors, make sure you set your db name and password correctly in config/database.yml (I made that mistake and got a weird error that said:

Couldn't create database for {"encoding"=>"utf8", "username"=>"root",
"adapter"=>"mysql", "host"=>"localhost", "password"=>nil,
"database"=>"todo_development", "pool"=>5}, charset: utf8,
collation: utf8_general_ci (if you set the charset manually, make
sure you have a matching collation)

All good? Now you can look at mysql and see your brand new databases

$ mysql -uroot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.0.67 MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| ....               |
| todo_development   |
| todo_production    |
| todo_test          |
+--------------------+
6 rows in set (0.00 sec)

mysql> exit

You can try other fun rake commands...

$ rake db:charset

(in /Library/WebServer/Documents/todo)
utf8

$ rake db:version

(in /Library/WebServer/Documents/todo)
Current version: 0

Here's a handy table of Rake database tasks from Akita:

db:charset Retrieves the charset for the current environment's database
db:collation Retrieves the collation for the current environment's database
db:create Create the database defined in config/database.yml for the current RAILS_ENV
db:create:all Create all the local databases defined in config/database.yml
db:drop Drops the database for the current RAILS_ENV
db:drop:all Drops all the local databases defined in config/database.yml
db:reset Drops and recreates the database from db/schema.rb for the current environment.
db:rollback Rolls the schema back to the previous version. Specify the number of steps with STEP=n
db:version Retrieves the current schema version number

Akita says... If we want to start from scratch, we can do db:drop:all. And in the middle of development we can do db:rollback to undo the latest migration file.

Ok, now you have some databases, but there is nothing in them

mysql> show tables;
Empty set (0.00 sec)

 


Generate Scaffold

Hold on to your hat and types these two lines into your terminal....

Note: the text you type is highlighted gray, the other text is expected output

./script/generate scaffold Category title:string

exists  app/models/
exists  app/controllers/
exists  app/helpers/
create  app/views/categories
exists  app/views/layouts/
exists  test/functional/
exists  test/unit/
exists  public/stylesheets/
create  app/views/categories/index.html.erb
create  app/views/categories/show.html.erb
create  app/views/categories/new.html.erb
create  app/views/categories/edit.html.erb
create  app/views/layouts/categories.html.erb
create  public/stylesheets/scaffold.css
create  app/controllers/categories_controller.rb
create  test/functional/categories_controller_test.rb
create  app/helpers/categories_helper.rb
route  map.resources :categories
dependency  model
exists    app/models/
exists    test/unit/
exists    test/fixtures/
create    app/models/category.rb
create    test/unit/category_test.rb
create    test/fixtures/categories.yml
create    db/migrate
create    db/migrate/20081213223324_create_categories.rb

rake db:migrate

(in /Library/WebServer/Documents/todo)
==  CreateCategories: migrating ===============================================
-- create_table(:categories)
-> 0.0032s
==  CreateCategories: migrated (0.0034s) ======================================

What just happened? Let's go back to mysql and check it out.

mysql> use todo_development;
Database changed

mysql> show tables;
+----------------------------+
| Tables_in_todo_development |
+----------------------------+
| categories                 |
| schema_migrations          |
+----------------------------+
2 rows in set (0.00 sec)

mysql> show columns from categories;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| title      | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime     | YES  |     | NULL    |                |
| updated_at | datetime     | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

Now with a little help from fairleads, let's poke around what rails has generated for us..

./script/server

=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails 2.2.2 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no restart).
** Rails signals registered.  HUP => reload (without restart).  It might not work well.
** Mongrel 1.1.4 available at 0.0.0.0:3000
** Use CTRL-C to stop.

Note: In development mode, Rails does not generally require you to stop the server; changes you make in files will be automatically picked up by the server.

point your browser at: http://localhost:3000/categories

You'll see a page generated from the rails view

You can use the links to create new catgories...

then when you go back to the categories page, you will see that is dynamically displays the list of categories


What did we learn?

  • By typing 4 lines into your terminal you can create a database application with basic (CRUD) list operations:
    
    rails -d mysql todo
    rake db:create:all
    ./script/generate scaffold Category title:string
    rake db:migrate
    
  • You can run your application using the Rails browser

    
    ./script/server
    point your browser at: http://localhost:3000/categories
    
  • There's still a lot of magic going on, which we'll learn about on day 2

Stay tuned.

Posted in code | 1 Comment

great ruby book

I am enjoying reading Mr. Neighborly’s Humble Little Ruby Book by Jeremy McAnnally. It’s a very easy read. I just finished chapter 3, and even though I’ll likely read the whole thing in the free PDF, I’ve ordered the print version to support this wonderful author and also I expect it will make a handy reference.

Along with the naturally dry instruction on the ins an outs of a programming language which he explains quite well, he includes humourous sample code and makes little language quirks delightfully easy to remember, such as:

For example, if you were creating a roleplaying game and wanted to set the possible ranges for the height of each race (in inches), you could type:

human = 48..81
elf = 40…68
grotesquely_huge_guy = 120..132

Ranges can use either two dots, which indicates an inclusive range of all values including the beginning value and the end value, or three dots, which excludes the last value. This seems backwards at first glance, but in truth that third dot is so fat that it pushes the last element out of the range. I am not kidding; crack open a debugger and find out for yourself.

Posted in code | 2 Comments

pipes, redirects and awk -v

I wanted to take the output of a command and put it in a temporary variable so I can append a string to it. (Trying to script perforce to append something to my client spec without interactive involvement.)

First attempt:
$ p4 client -o > $CLIENTSPEC
c:\cygwin\bin\bash: $CLIENTSPEC: ambiguous redirect
I later learned that redirect is only for files.

Next attempt:
$ TEST=`p4 client -o`
$ echo $TEST
//depot/apps/diamond-calendar-preview/… //sallen-LENOVO/svn/openlaszlo/branches/pagan-deities/diamond-calen //depot/apps/diamond-amaranth-ms2/… //sallen-LENOVO/svn/openlaszlo/branches/pagan-deities/diamond-amaranth- //depot/sandbox/my-webtops/… //sallen-LENOVO/svn/openlaszlo/branches/wafflecone/diamond/client/my-webtops/. ..
which seems to have swallowed line endings and only provided the last few lines of output.

My colleagues at Laszlo, Trebor Fenstermaker and Chris Pettitt and ptw, showed me the error of my ways and provided some good tips. Trebor noted that there is a length limit for shell variables and that line endings will get lost. Chris introduced a combination of pipe and awk -v which did the trick. At first I thought Tucker’s simple echo solution wasn’t working, but he pointed out that I just needed to properly parenthesize my commands.

What worked:
p4 client -o | awk -v append=” //depot/apps/test/… //sallen-test/svn/openlaszlo/branches/pagan-deities/test/…” ‘{ print $0 } END { print append }’ | p4 client -i

Even simpler:
(p4 client -o; echo ” //depot/apps/test/… //sallen-test/svn/openlaszlo/branches/pagan-deities/test/…” ) | p4 client -i

Notes:

  • Redirect only works for files, there are lots of different types of redirects (> is a simple redirect of stdout to a file, >> will append to a file, 2> will redirect stderr)
  • awk -v will define a variable which can then be used in the awk script
  • You need to properly parenthesize your commands:

    ( p4 client -o; echo “Thing to append” ) | p4 client -i

    The parens will execute the p4 and echo commands in a sub-shell so the output of both will be piped to the next. Without the parens you have said:

    p4 client -o; ( echo “Thing to append” | p4 client -i )

    I.e., run the client command, then run echo to a pipe.

  • Pipe will let you take the stdout of one command and send it to the stdin of another:
Posted in code | Leave a comment