Creating the Project and a Basic Administration Interface

I’m working on two main projects this summer. One is a sequel of sorts to my work on Genetic Development. I have note posted anything on that yet. The other is “Notes on Rails,” the new project that had me pick up Agile Web Development with Rails — 2nd Edition, which is an amazing book for learning that framework.

Both of these tie into my desired research program, but because Notes on Rails is a bigger project I will blog them in in different ways. Expect the developmental work to start posting when its about half done, but I will post the progress of “Notes on Rails” as it happens.

Why? Same reason I blog anything: my benefit. I found during my first semester at UNL that I understand the material better if I re-present it. So hopefully this will allow me to understand my work better. And if someone gets interested in Ruby on Rails because of what I do with it… so much the better

For those who do read on: beware! Few things are as ugly as thinking out loud in a language you don’t understand!

Hierarchicacly, the project can be understood that every experiment can have multiple conditions, every condition will have pre-set rows and columns as well as dynamically set users. Every distinct user at every distcint row and column makes a distinct note:

Experiment 1
+Condition 1
++User 1
+++Row 1 x Col 1 = Note 1


The program can be walked through as either a user or an admin. The user for identifies himself, takes any needed pre-tests, reads a text which he can take notes on, and then takes post-tests.

The admin, after logging in, can either view reports, or add experiments and conditions.

We’ll get a good start on the admin interface today.

All page numbers are from Agile Web Development with Rails, 2nd Edition.

Will call this NotesOnRails, so first we rail a project called notes01 (68)

rails notesonrails

Then we create a database for this to exist in (69)

mysqladmin -u root create notesonrails_development

To test if this works, rake the database to migrate it to its current state (71)

We’ll create the basic tables now. First list create the “experiment” table (75)

ruby script/generate model experiment

Then I edit the new database migration file created (db/migrate/001_create_experiments.rb) (75)

class CreateExperiments < ActiveRecord::Migration
def self.up
create_table :experiments do |t|
t.column :name, :string
t.column :description, :text

def self.down
drop_table :experiments

Then rake it again to see if it works ok (75)

rake db:migrate

Create an admin controller (76)

ruby script/generate controller admin

And edit the generate app/controllers/admin_controller.rb to scaffold the experiments (76)

class AdminController < ApplicationController
scaffold :experiment

Then run the instantrails web server

ruby script/server (77)

And check out the functionality at localhost:3000/admin

For some cleanup, I’ll edit the model class for “Experiment” so that it validates the name and the description (82) and makes sure the name is unique (85)

class Experiment < ActiveRecord::Base
validates_presence_of :name, :description
validates_uniqueness_of :name

The rest of Chapter 6 deals with making the interface prettier, which I’m not concerned with now.

Some final stuf:

We already created the experiments table/model. Now let’s do the Conditions, Rows, and Columns ones as well (recall back to 75):

ruby script/generate model condition
ruby script/generate model row
ruby script/generate model column

This creates a number of files in the db/migrate folder (002_create_conditions.rb, 003_create_rows.rb, 004_create_columns.rb). We’ll edit each of these in turn. 002_create_conditions will be added to insert a name and description for each condition

class CreateConditions < ActiveRecord::Migration
def self.up
create_table :conditions do |t|
t.column :name, :string
t.column :description, :text

def self.down
drop_table :conditions

We’ll do this same change for 003_create_rows.rb, and 004_create_columns.rb.

t.column :name, :string
t.column :description, :text

Then, rake db:migrate

Add the new scaffolding instructions to our admin controller(app/controllers/admin_controller.rb)

Now we can create specific controllers for each of these modules/tables (looking back to page 76)

ruby script/generate controller manage_experiments
ruby script/generate controller manage_conditions
ruby script/generate controller manage_rows
ruby script/generate controller manage_columns

Add the appropriate “scaffold: ” to each of your _controller.rb ‘s as appropriate

scaffold :experiment…
scaffold :condition…
scaffold :row…
scaffold :column…

Start up the web server (ruby script/server) and load it up (localhost:3000/admin/manage_ &c).

I want to finish up the administration interface, so I’m jumping to the description of has_many and belongs_to on the 140s pages in the book. I’m going to take our graph of the tables (“models”) that was earlier in the post

and add the relations to the models file in ruby.

First, we need to alter the above tables to include the foreign keys necessary to make this all work. To do this we will add a migration to add the foreign keys

ruby script/generate migration add_foreign_keys

This creates the file 005_add_foreign_keys.rb

Edit that file so that it reads (266-267)

class AddForeignKeys < ActiveRecord::Migration
def self.up
add_column :conditions , :experiment_name, :string
add_column :rows , :condition_name, :string
add_column :columns , :condition_name, :string

def self.down
remove_column :conditions, :experiment_name
remove_column :rows, :condition_name
remove_column :columns, :condition_name

And rake db:migrate

Then, alter the module files (experiments.rb, &c) to add these relations to the ruby on rails framework

So experiment.rb will now read

class Experiment < ActiveRecord::Base
validates_presence_of :name, :description
validates_uniqueness_of :name

has_many :conditions

In condition.rb, make the name unique (because its a foreign key) and add its logic

class Condition < ActiveRecord::Base
validates_uniqueness_of :name

belongs_to :experiment
has_many :rows
has_many :columns

Both row.rb and column.rb have the same body

validates_uniqueness_of :name

belongs_to :condition

That’s it for today!