« July 2007 | Main | April 2008 »

October 5, 2007

Newbie Ruby on Rails with Locomotive, Part 2

Thanks to http://safari.oreilly.com and the O'Reilly Rails Cookbook, I have learned the answer to my burning question:

Yes, I *do* need to create join tables in my database migration definition files.
It wasn't clear to me at first, but now what I'm realizing -- and hopefully this is correct -- is that the rails migration schema file is really just an abstracted way of writing a database setup script. Rails can translate its file into the setup script for whatever database you're using, but you still have to specify all the joins, defaults, etc. just as you would if you were setting up the database in its native language. Check and check.

I do use the scaffolding command to create multiple model-controller relationships. (See O'Reilly OnLamp: Rolling with Ruby on Rails Revisited.)

"test" is a reserved word.
This is apparently a problem. I'm building a DB to track usability tests, and I named one of my tables "test". I'm trying to migrate to "usabilitytests" but i'm running into problems. Solved by deleting the entire app and recreating. Obviously not something that one would always want to do, but I don't know how to un-create models and controllers and whatnot that have already been set.

functions in the controller are lowercase with underscores.
I'm not entirely sure of this, but I downloaded a sample application and checked out that code.

TOTALLY STUMPED: Radio buttons in RoR?
Okay, I found the documentation for how to render a checkbox. Am I smoking crack? Did the entire RoR project forget about the existence of radio buttons? From an interaction perspective, radio buttons are the exact same as SELECT boxes: They afford one-from-many selection. They're just rendered in an easier-to-read and easier-to-operate widget. (Select boxes are hard for people to use, and even if you know what you're doing, they're way more of a pain particularly for administrative-type applications when you interact with the box a billion times a day.) I expect there to be a function like collection_radio that operates almost exactly the same as collection_select -- but as far as I can tell, no such thing exists.

My Total Novice Experience: Ruby on Rails with Locomotive

I'm going to spare you the discussion on what Ruby on Rails is and why you'd want to use it. Lots of other people have covered that. A quick word about my background:


  • I am a very good HTML, Javascript, and CSS "coder".

  • I am a moderately proficient PHP programmer, which I use to create prototypes for usability tests and whatnot.

  • I am nigh-on retarded when it comes to hooking a webapp to a MySQL database. Ergo, I usually don't get beyond the prototype stage for a lot of cool webapp ideas I've had.

  • I can muddle along in a handful of other languages and frameworks, like Perl, Java, Clearsilver, Struts, and XSLT.

  • I have zero exposure to Ruby, Python, Gems, etc.

  • I'm good at programming -- thinking in abstractions, being efficient, breaking down a goal into minute logical steps, etc.

My goal: I'm helping a friend create a usability testing infrastructure for his startup. I want to create a website to recruit participants for various studies, let people sign up to be a participant, and do some lightweight CRM of when they were contacted, outcomes, and whether they have already participated in a test.

Requirements:

Participant:

Firstname Surname Phone Country Timezone Email(unique) DateOfSubmission Age Gender Occupation Industry Education ContactForFutureTests? NativeLanguage Status[ New | AssignedToTest | Archived | CompletedTest ] NOTES

Note: (Each participant can have several notes)
Author Timestamp ParticipantID NoteText

Test: (Each test has several participants)
TestID Status[ Active | Complete | Pending ] Date Description ConsentFormURL Compensation PARTICIPANTS

TestParticipant:
CompensationGiven ConsentFormSigned? ConsentFormID

ConsentForm
UniqueID HTML TestID

Note that this is NOT tied to the actual test data in any way -- that's not the point. This app is just to keep track of who we talked to and when. It's a very lightweight CRM.

I had a no-problem installation of Locomotive, the Mac OS X bundled installation of Ruby on Rails. I got my little app up and running on my Mac.

But now, what the frack do I do?

I need to tell it my database schema: the start page says "Create your databases and edit config/database.yml"

I open database.yml. It looks like it's already set up a database:

development:
adapter: mysql
database: UsabilityParticipants_development
username: root
password:
host: localhost

Is this true? Do I have a MySQL database running? Or do I need to go create one now, named Usability_Participants? (I have MySQL installed already but it's not running now.)

On to the internet: I go to http://developer.apple.com/tools/rubyonrails.html. Blah blah blah install, blah blah blah create an application. Locomotive did that for me. Ah-ha: Jump-Starting the Application sounds like where I'm at.

And here's the money shot: "Now we need to actually create the expenses_development database. Feel free to use whatever tool you're comfortable with. Here's how to create the database using the mysqladmin command-line tool:"

Thank you, Apple tech writers! I have the visual MySQL application installed in my Mac preferences panes, so I start up my server. I open up a terminal window. I run the suggested command and this happens:

ellen-beldners-computer:~ ellen$ $ mysqladmin -u root -p create UsabilityParticipants_development
-bash: $: command not found

Okay, so maybe I need to reinstall MySQL...? Google for [install mysql mac os x]; Apple recommends this installation package. It took about 400 clicks to get to the actual download link for Mac OS 10.4 x86....

Installed and running. let's try that command again:

 mysqladmin -u root -p create UsabilityParticipants_development
Enter password: [return]

Argh. Okay, what's the default mysql password for root? Hmm, I need to set it:

mysqladmin -u root password {whatever}

(Also, shouldn't I be creating non-root accounts for these databases and having custom passwords for each? I have no idea what I'm talking about, really, but I know that "root" usually means "all powerful and really scary things can happen".)

Once again:

ellen-beldners-computer:~ ellen$  mysqladmin -u root -p create UsabilityParticipants_development
Enter password:
mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'UsabilityParticipants_development'; database exists'

You bastards! You already created the database? Or did I? Fine. Be that way.

{I write a lot more, and then I SAVE this article, and in the meantime my router crashes, so firefox hangs, and i lose a lot.)

Basically, what happens is Apple tells me to set up a migration to specify my database schema. I enter the command and i get an error message

ellen-beldners-computer:~/UsabilityParticipants ellen$ script/generate migration participant
Cannot find gem for Rails ~>1.2.3.0:
    Install the missing gem with 'gem install -v=1.2.3 rails', or
    change environment.rb to define RAILS_GEM_VERSION with your desired version.

I ponder reinstalling, but that seems really scary given all the ways that Ruby on Rails can fuck your computer up. So I go into my environment.rb file and make it like this:

# RAILS_GEM_VERSION = '1.2.3' unless defined? RAILS_GEM_VERSION
RAILS_GEM_VERSION = '0.9.2'

(My environment variables at localhost:3001 told me I was running 0.9.2'.)

And now my application won't start at all.

# RAILS_GEM_VERSION = '1.2.3' unless defined? RAILS_GEM_VERSION
RAILS_GEM_VERSION = '0.9.2' unless defined? RAILS_GEM_VERSION

doesn't work either. Meh. All right, I'm starting over. Delete the Locomotive Rails ap, delete the files, and create a new one with the same name. Same thing happens:

Cannot find gem for Rails ~>1.2.3.0:
    Install the missing gem with 'gem install -v=1.2.3 rails', or
    change environment.rb to define RAILS_GEM_VERSION with your desired version.

I don't even know what this means!!! My environment variables are


Ruby version 1.8.6 (i686-darwin8.9.1)
RubyGems version 0.9.2
Rails version 1.2.3
Active Record version 1.15.3
Action Pack version 1.13.3
Action Web Service version 1.2.3
Action Mailer version 1.3.3
Active Support version 1.4.2
Application root /Users/ellen/UsabilityParticipants
Environment development
Database adapter mysql

I think that the Apple site is maybe not my best bet at this point. Google [rails application with locomotive] and the second link or so is an ars technica article. They're usually pretty good.... but not in this case. Did you actually write an article on dragging locomotive into your Applications folder? Assholes. That doesn't tell me anything.

Here's the official Rails tutorial on Migrations. Same command, same problem:

ellen-beldners-computer:~/UsabilityParticipants ellen$ ruby script/generate migration participants
Cannot find gem for Rails ~>1.2.3.0:
    Install the missing gem with 'gem install -v=1.2.3 rails', or
    change environment.rb to define RAILS_GEM_VERSION with your desired version.

After some more searching, I found this lovely tutorial on a first rails app with locomotive. Following all the directions to the letter, I typed


ellen-beldners-computer:~/UsabilityParticipants ellen$ ruby script/generate migration create_participants
create db/migrate
create db/migrate/001_create_participants.rb

It worked! Yay! I have no idea why it worked this time but didn't before; this time I openend the terminal window from Locomotion, but before, I had doubled checked to ensure I was in the right directory. Weird. Maybe it didn't set up my paths correctly and stuff??

I open the 001_create_participants.rb file. I now need to tell it about my database; but first I take a few minutes to sketch out exactly how I want my pages to flow to ensure that I'm capturing all the information I'll need to make it work.

list of Ruby on Rails migration database datatypes

So I edited my .rb file to be like this:


class CreateParticipants < ActiveRecord::Migration
def self.up
create_table :participants do |table|
# note that "id" is added implicitly, by default
table.column :firstname, :string
table.column :surname, :string
table.column :namepronunciation, :string
table.column :email, :string
table.column :phonenumber, :string
table.column :country, :string
table.column :timezone, :string
table.column :dateofsubmission, :datetime
table.column :age, :integer
table.column :gender, :string
table.column :occupation, :string
table.column :industry, :string
table.column :nativelanguage, :string
table.column :futurecontactokay, :boolean
table.column :status, :string
end

def self.down
drop_table :participants
end
end

I save and type the "rake migrate" command, which results in the extremely unsatisfying

rake aborted!
./db/migrate//001_create_participants.rb:25: syntax error, unexpected $end, expecting kEND

Investigation reveals that I was missing an "end" to close my "do" statement, rerun the command, and get:


ellen-beldners-computer:~/UsabilityParticipants ellen$ rake migrate --trace
(in /Users/ellen/UsabilityParticipants)
** Invoke migrate (first_time)
** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:migrate
== CreateParticipants: migrating ==============================================
-- create_table(:participants)
-> 0.0399s
== CreateParticipants: migrated (0.0401s) =====================================

** Invoke db:schema:dump (first_time)
** Invoke environment
** Execute db:schema:dump
** Execute migrate
The rake task migrate has been deprecated, please use the replacement version db:migrate
ellen-beldners-computer:~/UsabilityParticipants ellen$

So I need to figure out what this updated "db:migrate" thing means. blerrrrrgh..... it means the correct command is

rake db:migrate

Based on the information in the official rails tutorial on migrations, I am now supposed to create a model. Here's what happens:


ellen-beldners-computer:~/UsabilityParticipants ellen$ ruby script/generate model Participant
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/participant.rb
create test/unit/participant_test.rb
create test/fixtures/participants.yml
exists db/migrate
Another migration is already named create_participants: db/migrate/001_create_participants.rb

What does this mean? I don't know. Does it work? Is it broken? Should I do something else? Oh. Scaffolding:


ellen-beldners-computer:~/UsabilityParticipants ellen$ script/generate scaffold participants signup
exists app/controllers/
exists app/helpers/
create app/views/signup
exists app/views/layouts/
exists test/functional/
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/participants.rb
create test/unit/participants_test.rb
identical test/fixtures/participants.yml
create app/views/signup/_form.rhtml
create app/views/signup/list.rhtml
create app/views/signup/show.rhtml
create app/views/signup/new.rhtml
create app/views/signup/edit.rhtml
create app/controllers/signup_controller.rb
create test/functional/signup_controller_test.rb
create app/helpers/signup_helper.rb
create app/views/layouts/signup.rhtml
create public/stylesheets/scaffold.css

I'm able to go

http://localhost:3000/signup
and it works! All right!