comfort zones are for sleeping

Saturday, September 15, 2007

The Depot App: Task A

In the spirit of my last post, I have decided to jump right in, dang the torpedos, and start writing the Depot app that's explained in Chapter 5 of the Hiney Book. As we move through the tutorial, Hiney pretends that we've got some chick sitting beside us telling what she wants (like they always do), and that we have the opportunity to RoR shine as a true Rapid Application Development platform, easily responding to her every whim as she reveals her inmost desires more and more while working through successive iterations. Turns out her inmost desires revolve around selling programming books, so apparently she's an uggo.

This app needs a maintenance feature for adding, editing, and deleting products in the database - that's the feature that we'll create first, or rather, that's the feature we'll have Rails create for us first. Before we can do that we must create a new Rails app and a database for our product data.

A while back, I told you guys I found an editor I like for Ruby on Rails programming. Well let me tell you what: RadRails makes what little RoR programming I've done so far dead simple. I won't go far into describing it; the main things I like about it are that it gives me a project-level view of the app I'm creating, formatted and color-coded editing for ruby code files and other types of files for my app, and easy non-console access to the various services I need while I'm creating a Rails app (WEBrick, MySql, etc.). You have to do a little bit of reading to get it set up and ready to use, but you're reading this so I assume you can read help files too. I told it I wanted a new Rails project called depot, and voila!, there it is, ready to start programming.

The only thing I haven't figured out how to do in RadRails so far is create a new MySql database (I'm sure you can use RadRails for that, I just haven't figured out how). So I brought up a console window and typed this:



c:\rubysandboxdepot> mysql -u root -p
Enter password: ********
Welcome to the MySQL monitor. Commands end with ; or /g.
mysql> create database depot_development;
mysql> create database depot_test;
mysql> create database depot_production;
mysql> grant all on depot_development.* to 'root'@'localhost';
mysql> grant all on depot_test.* to 'root'@'localhost';
mysql> grant all on depot_production.* to 'root'@'localhost';
mysql> exit





Then I created a .sql file called schema.sql and saved it to the db folder:


drop table if exists products;
create table products (
id int not null auto_increment,
title varchar(100) not null,
description text not null,
image_url varchar(200) not null,
price decimal(10,2) not null,
date_available datetime not null,
primary key (id)
);

Actually, it was a little bit different than this when I first created it, but that's what it looked like at the end of all the iterations for Task A. I won't bore you with the details of the changes. The thing that really struck me was how easy and it is to change things in this environment - instant gratification.

Now to create the Admin feature, all I had to do was go to the generators tab in RadRails and tell it I wanted to generate a scaffold called Product Admin. That got me a "model" file called product.rb, a file to create unit tests for product.rb, and a bunch of views for doing CRUD on Products. I love how Rails assumes you're a big boy, and that you actually intend to write automated tests for your code - I've spent the last couple of years learning about TDD in .Net (among other things), and I'm very impressed that Rails has support for this built right in.

So now the Product class -


class Product < ActiveRecord::Base
validates_presence_of :title, :description, :image_url
validates_numericality_of :price
validates_uniqueness_of :title
validates_format_of :image_url,
:with => %r{\.(gif|jpg|png)$}i,
:message => "must be a URL for a GIF, JPG, or PNG image"

protected
def validate
errors.add(:price, "should be positive") unless price.nil? || price >= 0.01
end
def self.salable_items
find(:all,
:conditions => "date_available <= now()",
:order => "date_available desc")
end
end



I've got some questions I'm sure will be answered in due time as I learn about Ruby and about ActiveRecord, but for now there are some things that seem strange to me as I approach this from Redmond:

  1. Where are my properties? How does a Product know what information it needs to keep handy about itself? I imagine this is somewhere in the ActiveRecord pattern.
  2. All of those validates_* statements at the top of the class are static methods, I think. Are we overriding stuff in the base ActiveRecord class here? I know these things, along with the validate() method at the bottom of the class, are called when a product is saved. But what exactly is the mechanism that executes these methods?

The only other stuff we did in Task A was to tidy up the views a little - seems rather like old ASP code, but I'm sure there's a lot more stuff going on here.

1 comment:

Mason Browne said...

I implore you... for schema work, check out "migrations". They might not be in your book, but when building applications, I've found them to be priceless. Not only is the syntax a bit more Rails-y (since migrations are written in a Ruby, using a DSL), but the end product is you get a versioned schema (so you can roll back to a different migration if you broke something), nice files to keep in version control, and an auto-generated schema file which is always filled with your latest database schema.

Lovely stuff.