comfort zones are for sleeping

Tuesday, September 25, 2007

Depot App: Heads Down

I really am coding the Depot app. I promise. I'm just not blogging about it right now.

This blog is as much for my use as anyone else's, so I fully intend to go back and document my thoughts as I worked through each Depot task.

Stay tuned.

Thursday, September 20, 2007

Task A: Mea Culpa

OK, so I got some stuff wrong. Sue me. The point of this blog is to show that a .NET programmer can learn the RoR way of creating web apps. That means I'm learning; that does NOT mean I already know this stuff.

I had some questions about my Product class, specifically these lines:

  validates_presence_of :title, :description, :image_url
validates_numericality_of :price
validates_uniqueness_of :title
validates_format_of :image_url,
:with => %r{\.(gifjpgpng)$}i,
:message => "must be a URL for a GIF, JPG, or PNG image"
Apparently Ruby likes to call these declarations, and they are executed when the class is instantiated. I'm still guessing about some things: in my head, I'm assuming that these are instance properties whose values get set by the constructor. Then when the validate() method gets called as the object is saved, it checks the value of these properties as part of the base validate() logic. Am I anywhere near right on this?

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.

Friday, September 14, 2007

Let's Kill Something

I have two large posters hanging above my desk in my den of programming iniquity. One shows a fuzzy kitten dangling precipitously on a clotheswire by his claws, with the caption, "Hang in there!" The other shows two vultures, and one is saying to the other, "To heck with patience! Let's kill something!" I keep them where I can see them because I feel they represent the two sides of the coin that is my personality, the yin and the yang, if you will, of what makes me...well, me.

You see, I could sit back and wait patiently, obedient to my supposed fate, and hope someone or something comes along to sever my bond of ignominy, whether it be the shame of my own fear and weakness in the face of seemingly insurmountable odds, or my exile to the shadows until the end that approaches us all overtakes some hapless soul, and I receive my carrion feast like crumbs from the table. Patience is indeed a virtue. But it becomes a tether when I know I could throw it to the wind, cast my lot with that impudent vulture, spread my leathery wings to fly off into the night's cold embrace, and eat my fill until the juice runs down my neck.

I considered the message of both posters this evening as I sat in my dim parlor of digital ephemera, abuzz with the whir of heat sink fans, the clicking of hard drives, and the crackle of Tesla coils. Surrounded by hand-rubbed mahogony wainscot alive with the musk of decades worth of linseed oil, I eased back into my leather chair, and scratched my black jaguar Mr. Tinkles on the chin as he squinted, flattened his ears, and purred his familiar blessing. I took a slow, deliberate swig from my snifter of cognac and gazed deeply into the gems (rubies, ironically!) set deep in the eyesockets of the polished silver death's head mounted atop my ebony cane, as I pondered my decision. And then it came to me:

Let's kill something. Starting with a fuzzy kitten.

To whom it may concern

My machine is now back among the living. After re-seating the CMOS battery, and spending some time on the phone with the good people of the Dell support center (yes, you read correctly), I have video again. Among other things, I apparently inadvertently put my flat panel monitor into digital mode last weekend, but my motherboard video out is VGA. Laugh if you must.

A summary of the “help” I’ve received so far:

  • “Dude, sounds like your motherboard’s fried.”
  • “Disconnect everything”
  • And my personal favorite, “Buy an iMac.”

I see how you guys are. Don’t worry, you’ll get yours…

Tuesday, September 11, 2007

A tale of woe, and a plea for help

Well, the worst has come to pass. I can only assume by your stunned silence that you have already guessed the source of my grief: that’s right, my graphics card on my home machine has died. This tragic event occurred last Thursday evening, and I have been basically without a machine to call my own ever since. For the bereft among you, I will bring the old board into my office tomorrow morning for a proper funeral. Viewing will be from 7:30 to 8:00 AM. In lieu of flowers, it is requested that donations be made to the .Net Newbie on Rails fund (cash only please, no personal checks). Needless to say, this is seriously cutting into my RoR programming and blogging. That ain't living, that's just barely surviving. Like a vampire eking out an existence on the blood of rats and birds he traps in the cemetery.

The machine in question is a Dell Dimension E521 with onboard video, but I can’t get a video signal from the onboard video, not even during POST. Nothing, nada, zilch (and no, the monitor is not the problem). I got a new card (EVGA 7300 GT) from Fry’s this weekend and tried installing it. Here are the scenarios I’ve tried so far with little or no luck:

1) Monitor hooked to fried card (well, obviously)
2) Monitor hooked to onboard video, with fried card still installed
3) Monitor hooked to new card
4) Monitor hooked to onboard video, with new card installed

Scenario #2 worked for a couple of hours on Sunday night, but it stopped working last night before I installed the new card – no idea why. None of the other scenarios has worked at all. Tonight I’ll try taking the new board out and going back to onboard video. Beyond that, I’m clueless as to what to do.

Here’s where you come in: HELP!!! I welcome any advice on getting this solved.

Austin on Rails meeting

Last night I went to the Austin on Rails meeting just for fun (I know, “Dude, you really need to get a life”). Man, this is where all the real nerds are: all hairy, poorly dressed, probably haven’t seen the sun in 3+ weeks, and all crazy smart. There was a lot of love in that room for people with poor grooming and few social skills.

Cool stuff though. There was a guy there from Amazon presenting AWS, particularly their “infrastructure as a service” stuff. Talked a bit about their Simple Storage Service, which is flexible storage you can access via a webservice priced under a scaled fee-per-use model, as opposed to a subscription for a big chunk of storage you may not ever use. He also quickly covered the Simple Queuing Service – the name says it all.

Then he went into the Amazon Elastic Computing Cloud service (EC2), which is basically a huge grid of virtual Linux servers that can be spun up dynamically via a webservice, again with a fee-per-service pricing model. This offers a pretty cool solution for apps with limited needs for bursts of scalability, as well as time-bound apps. You can set the servers to spin up on a particular schedule, or you can spin up new servers if your app’s performance characteristics pass some arbitrary threshold you specify. Some cool usages he mentioned were:
  • A company in India is using EC2 to process payroll once a month for several thousand employees.
  • Stanford Law School uses EC2 to process OCR transcription of millions of old legal documents.
  • The guy who presented created a time-bound app called ThursDate – a social network that only operates between the hours of 5:00 – 8:00 on Thursday night. The idea is that you have three hours to log on, upload pictures, videos, etc on Thursday night to find a date for Friday night. When the 3-hour session is over, everything disappears, and the app reappears anew next Thursday with no persisted info from the previous session. He has a chron job that spins up an EC2 image at the appropriate time, and the floodgates open.
Anyhoo, if none of this sounds remotely interesting, and you can actually get a date, you are to be congratulated: I commend you. However if, like me, you have no social life, these guys could be a pretty good support group: http://www.austinonrails.org/.

Monday, September 3, 2007

Blogging Code

Anybody out there have any tips on blogging code? I'm finding it more difficult than it should be to intermingle code and regular text, and make the formatting come out anywhere near where I want it.

Hello, Rails! Part Deux: Season of the Witch

OK, so dynamic-izing the Hello, Rails! app turned out to be a heck of a lot easier than I had assumed it would be. Well, not really - I mean I thought it would be pretty easy, after all this is just a Hello, World app, and RoR is advertised as high-productivity. But it was stinkin' easy, man.

Still in the Hiney book on chapter 4, I messed around with some code they said I should plug in here and there. I wanted to display the current time, plus link some pages together, no big deal. Here's what the code ended up looking like:


say_controller.rb

class SayController < ApplicationController

def hello

@time = Time.now

end

def goodbye

end

end

hello.rhtml

<html>
<head>
<title>Hello, Rails!</title>
</head>
<body>
<h1>Hello from Rails!</h1>
<ul>
<li>Addition: <%= 1+2 %> </li>
<li>Concatenation: <%= "Chew" + "bacca" %> </li>
<li>Time in one hour: <%= 1.hour.from_now %> </li>
</ul>
<% 3.times do %>Ho!<br/><% end %>
Merry Christmas!
<p>It is now <%= @time %></p>
<p>Time to say <%= link_to "GoodBye!!", :action => "goodbye" %></p>
</body>
</html>



goodbye.rhtml

<
html>
<
head>
<
title>See you later!</title>
</
head>
<
body>
<
h1>Goodbye!!</h1>
<
p>It was nice having you here.</p>
<
p>Say <%= link_to "Hello!!", :action => "hello" %> again.</p>
</
body>
</
html
>

Now I've got two pages that link to each other through the controller using the link_to helper method. And the hello.rhtml file sits up and does a few interesting little tricks itself. I'll leave it to you to figure out exactly what each line does. Easy, breezy, beautiful, Cover Girl.

What's next?
I'm glad you asked. I think I'm going to put down the Hiney book for a few days and focus on learning a bit about Ruby itself. I got a copy of
the Pickaxe Book, but I'm planning to go through Why's Poignant Guide to Ruby first. There's a dude here in town named Bret Pettichord, and when it comes to Ruby he's a major dude. In fact, he was recently awarded a Certificate of Awesomeness by the Awesomeness Awareness Council. Anyway, Bret sez he picks up Why's Poignant Guide and reads through it from time to time. So I figure if he gets something out of it, a guy like me should get a lot out of it.



Saturday, September 1, 2007

A good RoR editor

Found a good editor for RoR. It's called RadRails - they mention it on the RoR download page, down towards the bottom. Everything is falling into place...

Now, if I could only find something that would make blogging code a bit easier.

Hello, Rails

Well, it's here. The time has finally come for an actual RoR application. And since this is my first RoR application, I will follow the KISS principle: Gene Simmons is the coolest bass player ever. Granted, that's not really saying much. Bass players aren't exactly known for being cool, at least not the white guys anyway (have you seen Geddy Lee?). But I suppose being the coolest out of that crowd makes you worthy of some attention. And Gene always says, "Keep it simple, or I'll kick your Hiney!!" So I'm gonna dance the dance that's been passed down from father to son for generations of programmers: the time-honored Hello, World! app.

When we last left our intrepid hero, he was pooped. He had just finished successfully installing Ruby, RubyGems, Rails, WEBrick, and MySql, and he had pulled the sample app that ships with RoR up in a browser. There was the press conference, the autograph hounds, the paparazzi... It was quite a day. But now I have to write a real RoR app, and I still don't know anything about Ruby, or how to compile a Ruby program, how to navigate and manipulate the Rails framework, or anything! I don't even know what editor would work best for Ruby programming! Woe is me!

Never fear - Hiney's here! (Insert fanfare here) That's right, I'm back on the Hiney book (get your mind out of the gutter, Earl), chapter 4. Sez here Rails is an MVC framework. Let's not worry too much about what MVC is right now. Just know that in order to get Hello, Rails! up and running, we only need to worry about the V and the C, the View and the Controller. I want the app to say "Hello, Rails!" I need a view which will display stuff in a browser, and a controller whose job is to wake the view up and tell it what to do. RoR has a ton of stuff already built in to help us build each piece we need in a flash.

The Say Controller
So back in my command window, in the demo directory, I type this to generate a controller called Say:

c:\rubysandbox\demo<ruby script/generate controller Say

RoR thinks a minute, then spits out all this stuff:

exists app/controllers/
exists app/helpers/
create app/views/say
exists test/functional/
create app/controllers/say_controller.rb
create test/functional/say_controller_test.rb
create app/helpers/say_helper.rb

and then dumps me back out to a command prompt. Looks like it created some directories and files - whooptie-doo. Interesting filenames, though. There's a directory for views, another directory for controllers, the say controller file itself, another file apparently for unit testing the say controller, and something called say_helper.rb. Wonder what that is? Let's look at the controller - since I don't know what editor to really use, I'll just look at it in good ol' Notepad:

class SayController < ApplicationControllerend

I think Notepad is choking on some funky whitespace character in there. I think it's really supposed to look like this:

class SayController < ApplicationController
end

Ruby is a true object oriented programming language. This file contains a class called SayController that inherits all its behavior from another class called ApplicationController, kind of like the way I inherited my father's dainty hands and my mother's patchy facial hair. Thanks to modern medical science though, we don't have to accept nature's atrocities. Let's do some surgery on our class. We need to create an action, which the webserver will use respond to a url somebody types into the browser like this:

http://localhost:3000/demo/say/hello

Urls are a bit different in RoR apps then they are in .NET apps. In .NET apps, a url usually identifies a real physical resource residing somewhere on the webserver. In RoR, everthing in the url above up through and including
http://localhost:3000/ identifies the application we're trying to interact with. The say/ part identifies our say controller, and the hello part identifies the action we're about to add to the say controller. Here's what the SayController class looks like with the hello action added into it:

class SayController < ApplicationController
def hello
end
end


I added a method to the SayController class called hello. There's nothing in that method right now, but that's ok. Remember, SayController inherits a lot of behaviour from ApplicationController.

The hello View
A controller without a view doesn't do much. So let's create the hello.rhtml view and save it in the app/views/say directory:

<html>
<head>
<title>Hello, Rails!</title>
</head>
<body>
<h1>Hello from Rails!</h1>
</body>
</html>

Pretty simple stuff. But what do you want? It's just a Hello, World! app. Remember, notepad likes to hang ".txt" on the end of your filenames. So take a look in the app/views/say directory and make sure that the filename for the view is hello.rhtml.

Putting it all together
So here's what will happen: Somebody (probably me) will come along and type
http://localhost:3000/say/hello into a browser on this computer. Assuming WEBrick is running, RoR will know it needs to look at the demo application and run the hello action on the say controller. The say controller will tell RoR to look in the app/views/say directory for a view called hello.rhtml - notice how all the names of various things are matching up (the say controller and the say views directory, the hello action and the hello.rhtml view, etc). RoR expects files and directories to be in standard locations, and for action and view names to match. When that happens, life is easy. RoR looks in the view directory, grabs hello.rhtml, and spits it back out to the browser.

First, I have to make sure my webserver is running:

c:\rubysandbox\demo>ruby script/server

and then I'll browse to
http://localhost:3000/say/hello in Firefox. And whaddaya know, it works!! There it is, "Hello from Rails!" smiling right back at me in the browser!! Awesome.

Next time
So what did we do this time? We learned about controllers and views, we created a controller and a view using RoR standards, and we got a static page we created to come up in the browser. That's good enough for today. Next time, we'll add a bit to Hello, Rails! to make it a bit more dynamic. But not today. I gotta go buy some paint.