Troubleshooters.Com, Code Corner, Ruby Revival and Ruby on Rails Present

Rapid Learning Rails
Copyright (C) 2006 by Steve Litt
Note: All materials in Ruby Revival and Rails material are provided AS IS. By reading the Rails materials you are agreeing to assume all risks involved in the use of the materials, and you are agreeing to absolve the authors, owners, and anyone else involved with Ruby Revival of any responsibility for the outcome of any use of these materials, even in the case of errors and/or omissions in the materials. If you do not agree to this, you must not read these materials.
To the 99.9% of you honest readers who take responsibility for your own actions, I'm truly sorry it is necessary to subject all readers to the above disclaimer.


CONTENTS

About Rapid Learning Rails

With many computer languages, you can spend a weekend learning, then go to work. As long as you don't let them see you programming with the manual on your lap, and as long as you bill for only half your hours during the first month, and assuming you're a good programmer, your client or employer will believe you were a Ninja from the moment you were hired.

Rails is not such a language.

Rails is incredibly broad. To even show up at work, you need to know about its components, its deployment, its debugging strategies. You'll need quite a bit of practice under your belt.

"Rapid Learning Rails" helps you get to that point. "Rapid Learning Rails" is based on the Rapid Learning methodology (click here for flowchart of the Rapid Learning Process). In cycles, you'll learn terminology, then perform iterative and experimental learning.

Rails, also called "Ruby on Rails", is a web programming framework that takes care of most boring details of web programming, leaving you to program those things that make your web app unique. Many consider Rails the fastest web development framework around.

Basic Terminology


Rails
A framework for developing web applications.
Ruby on Rails
Synonym for Rails.
Ruby
The computer language used to write Rails, and also the language you use to turn the Rails framework into an application. Ruby is a loosely typed interpreter with a full yet simple object model, and in my opinion is a very productive computer language.
Web application
A computer program that interfaces with the user through a web browser.
Framework
A ready made bunch of code and code generators to perform the majority of a software program. It is then up to the application developer to add the code that makes his application unique. Such code is typically added in many different spots throughout the framework.
MVC
Stands for Model, View and Controller. Many web application frameworks, including Ruby, partition their code into models, views and controllers. Doing so makes it easier to change and scale the program.
Model
The part of the application that interfaces to persistant data, whether that data is stored in a DBMS (MySQL, Postgres, MS SQL Server, Oracle and the like), or as a flat file on the local disk, or some other way. The persistent data is accessed and validated by code in the model.

There is typically one model for each database table, and one for each relevent flat file.
View
The part of the application that paints screens. Ideally, code in the view paints the screen but does nothing else. Lookups and calculations are done elsewhere, and the view simply sends results of those lookups and calculations to the screen, properly formatted.

There is typically one view for each type of screen, although often one view is used for several similar but slightly different screens. For instance, screens for data insert, modification and deletion are all similar enough to be accomplished with one view using flags set by the controller.
Controller
The part of the application that does what the model and view don't. Some people claim the controller contains the "business rules". I consider that a little pompous. After all, many applications are not intended to be used just for business. Also, some business rules, such as "we don't accept anyone with a credit score under 500" are typically implemented in a model as validation routines.

Every Rails application has at least one controller. There might be more, but usually not a large number. One way of splitting the work is to create a controller for each type of person using the system. For instance, there might be one controller called DataEntryPerson, another called Accountant, and a third called Administrator.


DRY
Stands for Don't Repeat Yourself. This means have each piece of information in one place. This is a basic part of the Ruby philosophy, and of course is also the philosophy behind data normalization.
AJAX
Stands for Asynchronous JavaScript And XML. This technology enables a web page to communicate with the server and update parts of itself without refreshing the whole page, thereby saving bandwidth.
Webrick The web server that comes with Rails. You run it with this command:
script/server
It can serve only a single application on a single port, so it's more useful for development and testing than for production. Luckily, other web servers can serve Rails pages in production.
Apache
The market leader in web servers. Apache can serve Rails pages if you're willing to put in some deployment work.
InstantRails
Ruby, Gems and Rails, with production quality web server, in one bundle. Unfortunately, as of 1/18/2006 it's Windows only, but a Linux/Unix/BSD version is being worked on.
Locomotive
A production quality Rails-capable web server, which unfortunately is Mac only.
fastcgi

A system whereby CGI (Common Gateway Interface) programs stay in memory rather than being spawned as individual process when requested. This makes for much better efficiency. The lighttpd server comes with a fastcgi interface.
lighttpd Production quality, Rails-capable, Ruby-centric web server available for Linux/Unix/BSD. Requires fastcgi. See http://wiki.rubyonrails.com/rails/pages/Lighttpd and http://www.lighttpd.net/.
RubyGems A package manager for Ruby packages. Used to install Rails.
scaffold An autocoded chunk of code facilitating creation ofscreens to list out a data table, and to provide create, edit and delete facilities for a data table, based on the structure of that data table, which the scaffold generator reads and uses as a specification. You can use a few scaffolds to create a quick and dirty web app to show your client.
session
A hash like structure within Rails apps to hold state between pages. It's a front end to cookies, where the state info is really held.
flash
This is NOT Macromedia flash, and is nothing like Macromedia flash!

In Rails, the term "flash" refers to a facility to pass temporary objects between actions. It's a module: ActionController::Flash. Whatever you place in flash will be exposed in the very next action, but then deleted, so you don't need to delete it manually (which is why it's better than the session for this type of thing). It's often used for error, warning and informational messages displayed on the screen after one the user has just filled out.






Installation

Installing Rails is a sort of bootstrap process. First, if you don't have Ruby 1.8.2 or better, you must install it. Armed with Ruby, you must install RubyGems. Finally you use RubyGems to download and install Rails, and then test Rails:
  1. Install Ruby
  2. Install RubyGems
  3. Install Rails
  4. Test Rails

Install Ruby

You can skip this step if you already have Ruby 1.8.2 or better.

Download the latest Ruby tarball. For instance, I used ruby-1.8.4.tar.gz. My tarball defaults to installation in /usr/local/lib, /usr/local/lib/ruby, and /usr/local/bin. Such an installation can coexist with the ruby that ships with most distros, because they put their Ruby in /usr/bin. If those installation directories work for you, you can perform the default (and easy) method of installation:
The preceding replaces the old ruby executable with the new one. The old one is still available as ruby-1.8.1. The two calls to ruby -v test to make sure the new version is available. Once Ruby is installed, you're ready to install RubyGems.

Install RubyGems

RubyGems is a system to download, collect and organize various Ruby packages. It's something like Perl's CPAN. Read the README file to make sure you can perform the default install, and then, for the default install, do the following:
The final command tests to make sure it was actually installed.

Install Rails

Rails doesn't always install cleanly. I've seen several instances in which I had to install it repeatedly, without uninstalling the previous attempt, to get it to work. Ideally, here's the command to install it:
gem install rails --include-dependencies
When the preceding command finishes, run the rails command to verify that Rails was installed. If you see a "help" or "usage" screen, you succeeded.

If things go well, the gem install command will download Rails (so be sure your Internet connection is working) and install  it. If not, repeat the command without the --include-dependencies option, answering "yes" to dependency questions. Debian users take note: I repeatedly failed to install Rails on Debian, no matter how hard I tried, so be ready to do some research.

Once Rails is installed, it's time to perform a test.

Test Rails

If the two pages render properly, your Rails installation is in good shape.

Hello World

Now that you have a running version of Rails, here's a question for you. Do you have ten minutes to spare?

If so, try this Hello World type Rails program.

This exercise has four simple parts:
  1. Create the application directories
  2. Check for Gotchas
  3. Create controller and view for a static app
  4. Use controller instance variables in the view (and therefore the web page)

Create the application directories

First, create a directory where you (not root, you) have read, write and execute permissions. For the purpose of this tutorial we'll create a directory called tcrails under /home/slitt. We'll put all the applications developed in the exercises on this page in /home/slitt/tcrails. Obviously, you'll use your own username instead of slitt, or you can even put tcrails somewhere other than your home directory, but for the purposes of this tutorial we'll use /home/slitt/tcrails as the to contain all applications. So create your tcrails directory now, and then do the following.

cd /home/slitt/tcrails
rails hello

You'll see a several messages scroll by. You've just created the first part of your application's framework.

NOTE

If you need to redo the creation of an app, either press the "a" key when it asks about overwriting, or simply erase the application's directory (in this case hello ) and then rerun the rails hello command.

Now see what you've created with the tree hello command. The following is such a tree command, but with many of its 76 lines pruned for the sake of simplicity:

hello
|-- README
|-- app
| |-- controllers
| | `-- application.rb
| |-- helpers
| | `-- application_helper.rb
| |-- models
| `-- views
| `-- layouts
|-- config
| |-- boot.rb
| |-- database.yml
| |-- environment.rb
| |-- environments
| | |-- development.rb
| | |-- production.rb
| | `-- test.rb
| `-- routes.rb
|-- db
|-- doc
| `-- README_FOR_APP
|-- log
| |-- development.log
| |-- production.log
| |-- server.log
| `-- test.log
|-- public
| |-- index.html
| `-- stylesheets
`-- script
|-- generate
`-- server

Head of this application's tree
Basic documentation
The program files making up the application itself
Where you store all controllers



Where you store all models
Where you store all views
Where you store layouts to make "look and feel" uniform
Where Rails configuration is stored

Info to connect to the database.





Determines the URL to access the application



Logs stored here
Log used during development
Log used while in production
Log of the web server

Stylesheets used in the app, and Web pages outside the app
Default web page seen before application is developed
Stylesheets used in the application's pages
Scripts stored here
Used to generate views, models, controllers, and other entities
Runs this application in a server on a certain port

As you noticed, everything Rails created was created in  the newly created hello directory, which itself was created in the current directory. From now on, the directory that was created by the rails command will be referred to as the application directory. Do not confuse this with the app directory below every application directory -- the application directory is different for every application. In the case of this hello application, the application directory is:
/home/slitt/tcrails/hello
From now on, every directory and file discussed will be relative to the application directory, unless otherwise specified.

Now that something's been generated we can look at the default web page, which is  in the application directory's public/index.html. Perform the following command:
ruby script/server
You'll see several lines scroll by, and then the text will stop. If it gripes about Errno::EADDRINUSE , scrolls several lines and then terminates, the port the server attempted to use is probably already in use. In that case, try a different port. Make sure the other port is not used by anything else, and make sure using it doesn't constitute a security problem. I've used port 8818 in the past, and that worked for me. The server defaults to port 3000. To use a different port, do this:
ruby script/server -p 8818
You can substitute any safe port for 8818. For the rest of this tutorial we'll assume you're using port 3000. If you aren't, just substitute your port number.

Once you have the server running, browse to url http://localhost:3000. It should look something like this:

Rails welcome screen


If you got something like the preceding screenshot, you've proven that Rails is running, and you've created your first application, although it contains absolutely no code you've written.

Check for Gotchas

Rails has some gotchas that can bite you if you're not aware. A few that might bite you early in your career are discussed here:

The dreaded blank page

When working on a Rails app, you might find that the web page is blank. No messages, no errors, no code, no nothing. If you view source for the page, you see nothing. Worse yet, you can put in almost any web address related to your Rails app, even if the address doesn't exist, and you still get the blank page. It's a debugging nightmare if you're not aware of the cause.

The usual cause is a cookie problem. It has been seen in Mozilla and in Firefox, and probably occurs in many or all browsers. The immediate solution is to tell your browser to dump all its cookies, after which you'll see either the proper page or a legitimate error message.

My current understanding of the problem is that it is caused by old, stale session data which must be dumped. I will research exactly how to do that.

Because the dreaded blank page is intermittent and rare, a solution will take some time, but in the meantime, at least you know what you're dealing with.

Create controller and view for a static app

Now let's create a controller and view. Do this:
[slitt@mydesk hello]$ script/generate controller Greetings index
exists app/controllers/
exists app/helpers/
create app/views/greetings
exists test/functional/
create app/controllers/greetings_controller.rb
create test/functional/greetings_controller_test.rb
create app/helpers/greetings_helper.rb
create app/views/greetings/index.rhtml
[slitt@mydesk hello]$

In the preceding, you created a controller called Greetings and a view called index, which, by the way, is the default if the visitor doesn't specify a view. Looking at the output of the command, you see that it created, among other things, app/controllers/greetings_controller.rb, which is the source code for your controller, and app/views/greetings/index.rhtml, which is the markup code for your view. The .rhtml extension means *RAILS* html, a form of html that can take Rails variables and commands within <% %> or <%= %> tags. Now browse to http://localhost:3000/greetings or http://localhost:3000/greetings/index (remember that the index view is the default), and you'll see something like this:

Hello World, autogenerated, static

If you want to see where that comes from, just look at app/views/greetings/index.rhtml:

<h1>Greetings#index</h1>
<p>Find me in app/views/greetings/index.rhtml</p>

As you can see, all that happened is that html file got printed. No big deal.

Except how did the server (Webrick) know to serve out that particular file? The server plays a few tricks with the URL:
http://localhost:3000/greetings/index LEGEND:

Application
Controller
View
So the preceding URL says "In the app at localhost:3000, show me the index view of the greetings controller. As mentioned before, if a view isn't specified, it defaults to index.

Use controller instance variables in the view (and therefore the web page)

OK, big deal -- you could have written a 2 line html file to do what we've done so far. How about making it behave like a program?  What we'll do now use the index method of the GreetingsController class to create two instance variables for that class:
  1. @curdir contains the current directory of the running process.
  2. @title contains the title you want for the page.
Here's the new app/controllers/greetings_controller.rb, with the new lines marked in red:

class GreetingsController < ApplicationController

def index
@curdir = Dir.getwd
@title = "The Current Directory"
end
end

Now we'll use the title both in the browser title bar, and in the web page itself as a large, bold and centered title. Then we'll state the current directory. Both the title and current directory are printed using Rails' <%= @instance_var %> syntax, with instance variables set in greetings_controller.rb file. Edit app/views/greetings/index.rhtml so it looks as follows, once again with the new material in red:
Here's the new app/controllers/greetings_controller.rb, with the new lines marked in red:

<head><title><%= @title %></title></head>
<body>
<center><b><big><big><big><%= @title %></big></big></big></b></center>
<br>
<br>
The current directory is <%= @curdir %><br>
<br>
<h1>Greetings#index</h1>
<p>Find me in app/views/greetings/index.rhtml</p>
</body>

Notice we needed to add both <head></head> and <body></body> in order to print the title in both the browser's title bar and the web page itself. Here's the resulting web page:

Dynamic version of hello world

The ability to set variables in the controller and use them in the view gives us tremendous flexibility. We can totally change a web page's presentation without disturbing its logic.

Incidentally, you'd never do this on a live system -- it could be a security risk, and at the very least it would give badguys more info about your system than you'd want them to have.

What You've Accomplished

In this exercise you've used the rails hello command to create a new application, and then used the script/generate controller Greetings index command to generate stubs for the controller and the view (and also other stubs which we haven't gone into yet). Finally, you applied some logic in the controller to set some variables, and used those variables in the view.

Changing the App's URL

We already mentioned this:

http://localhost:3000/greetings/index LEGEND:

Application
Controller
View

There's an easy way to change the application part of the URL. You can go into config/routes.rb and change the routing:
ActionController::Routing::Routes.draw do |map|
# Add your own custom routes here.
# The priority is based upon order of creation: first created -> highest priority.

# Here's a sample route:
# map.connect 'products/:id', :controller => 'catalog', :action => 'view'
# Keep in mind you can assign values other than :controller and :action

# You can have the root of your site routed by hooking up ''
# -- just remember to delete public/index.html.
# map.connect '', :controller => "welcome"

# Allow downloading Web Service WSDL as a file with an extension
# instead of a file named 'wsdl'
map.connect ':controller/service.wsdl', :action => 'wsdl'

# Install the default route as the lowest priority.
#map.connect ':controller/:action/:id'
map.connect 'rails-demo/:controller/:action/:id'
end

In the preceding, the struck through part was originally not commented out, but we commented it and replaced it with the red line. Now the web page is accessible through this URL:
http://localhost:3000/rails-demo/greetings/index
As mentioned many times, the /index on the end is optional because index is the default view.

In a one controller app, we could change it so that it's accessible from the root of the domain:
map.connect '', :controller => "greetings"
The preceding mapping would bring up the index view at this URL:
http://localhost:3000/
However, that suffers from the problem that only the index view is accessible. To make all views of that single controller available at http://localhost:3000/, do this:
map.connect ':action', :controller => "greetings"
However, what you would typically do is leave the routing at its initial mapping:
map.connect ':controller/:action/:id'
Then you would remove the existing public/index.html page, and substitute a page that acts as a series of links to various controllers.

To facilitate coming exercises, please leave the mapping at its original:
map.connect ':controller/:action/:id'
There are still other mapping issues, such as hooking your site to an actual domain name, and getting rid of the visitor-intimidating port number. These are deployment issues that are discussed later in this document.

Implement links the Rails way

We all know how to do a link in HTML:
<a href="other_page.html">Click here</a> to see other page.
That's nice, and it's easy, but it mixes up logic flow with presentation, which, as we all know, can lead to maintenance and scalability problems. This article describes the Rails way to perform linking.

The first thing we need to do is create a second view. We'll call it page 2. While creating this, you'll be asked whether you want to replace existing material. Say no every time. All you're doing is creating a new view. You want to leave the existing view and the existing controller as they were:

[slitt@mydesk hello]$ script/generate controller Greetings page2
exists app/controllers/
exists app/helpers/
exists app/views/greetings
exists test/functional/
overwrite app/controllers/greetings_controller.rb? [Ynaq] n
skip app/controllers/greetings_controller.rb
identical test/functional/greetings_controller_test.rb
identical app/helpers/greetings_helper.rb
create app/views/greetings/page2.rhtml
[slitt@mydesk hello]$

Now edit app/view/page2.rhtml to look like this:

<head><title>This is the second page</title></head>
<body>
<center></b><big><big>This is the second page</big></big></b></center>
<br>
<br>
Go to <%= link_to "main page", :action => "index" %>
<h1>Greetings#page2</h1>
<p>Find me in app/views/greetings/page2.rhtml</p>

The link is accomplished by the embedded Rails code containing the link_to method. Notice that the text following the link_to method can be anything. It's simply the link text. The page is identified by the value associated with the :action key.

When making links, watch out for the following gotchas:
 The preceding code produces a page at http://localhost:3000/page2 that looks like this:

The page2 web page

When you click the main page link, you'll be brought to the index page. Try it.

Now we can put a link going the other way in the index page. In the following code, the new material is in red:

<head><title><%= @title %></title></head>
<body>
<center><b><big><big><big><%= @title %></big></big></big></b></center>
<br>
<br>
The current directory is <%= @curdir %><br>
<br>
<%= link_to "Click here", :action=>"page2" %>
to go to the second page.<br>
<br>
<h1>Greetings#index</h1>
<p>Find me in app/views/greetings/index.rhtml</p>
</body>

Now the index page looks like this:

Index page with link

Now you can click back and forth between the two. It works perfectly. But you're not done...

You've created a view for page2, but that view has no corresponding method in the controller. The lack of the method causes no harm in this simple exercise, but in real life you'll need it to perform the logic to load variables to be used by the view. So before going on, put a stub page2 method in the controller (app/controllers/greetings_controller.rb).

class GreetingsController < ApplicationController

def index
@curdir = Dir.getwd
@title = "The Current Directory"
end
def page2
end
end


That's it. You've implemented links.

Persistence

By far the toughest part of web programming is that the HTTP protocol, which is the protocol used by the web, is stateless. That means that every web page starts knowing nothing of web pages that came before it. Programs cannot be written under such circumstances.

For that reason, programmers from the dawn of time have found various ways to pass information between web pages:
All persistence kludges, and that's what they are, kludges to compensate for HTTP statelessness, are ugly, and every single page on the website must pass state info, even if such pages have no dynamic content, or else state is lost. URL passing is a horrible security faux pax. Passing in form variables means every single page on the website must pass state info, even if such pages have no dynamic content, or else state is lost. Passing in cookies has privacy implications, and some people turn off cookies on their browser.

The best a framework can do for you is to shield you, the application programmer, from the drudgery of maintaining state. Rails does this with a hash like structure called session. This hash like structure is your abstraction for cookies-based state maintenance. That's right -- Rails won't work if the browser has cookies turned off -- you need to warn the user to turn on cookies before proceeding to dynamic pages that need state.

To explore persistence, let's create a brand new app, called fibb, that prints the Fibbonacci number sequence:
In the Fibbonacci series, each number is the sum of the preceding two. Let's build our app and our controller, which in this case we'll name fibb and Fibb respectively. This app will have one page, index. We'll know we've succeeded when each web page refresh prints the next Fibbonnacci number.

Let's create the app and the controller now. The first thing you want to do is kill the server, Webrick, on your current application. Otherwise it will prevent your running a server on your new application. Find the terminal where Webrick is running, and terminate it with a Ctrl+C key combination. Then build the new app.

Get into the tcrails directory you created in the Hello World exercise, and do the following:
rails fibb
cd fibb
script/generate controller Fibb index
Now edit app/controllers/fibb_controller.rb so it looks like this:

class FibbController < ApplicationController
def index
unless @f1
@f1 = 1
@f2 = 1
end
temp = @f2 + @f1
@f1 = @f2
@f2 = temp
end

end

Edit app/views/fibb/index.rhtml to look like this:

<h1>Fibb#index</h1>
<p>Find me in app/views/fibb/index.rhtml</p>
f1=<%= @f1 %><br>
f2=<%= @f2 %><br>


Now run the server with this command:
script/server
Browse to http://localhost:3000/fibb and you'll see a screen something like this:

Original Fibbonacci screen

Now click the reload (or refresh or whatever) button, and watch what happens...

Absolutely nothing happens.

HTTP is stateless. Each time you reload the web page, @f1, @f2 and @f3 are once again redefined, and therefore are reinitialized. Oops.

Leaving the view alone, let's retool the controller to look like this:

class FibbController < ApplicationController

def index
unless session[:f1]
session[:f1] = 1
session[:f2] = 1
end
temp = session[:f2] + session[:f1]
session[:f1] = session[:f2]
session[:f2] = temp
@f1 = session[:f1]
@f2 = session[:f2]
end
end

The first time you run the view it looks the same. Then, as you click the browser's reload button, the numbers start to change, with f2 going first to 2, then 3, 5, 8, 13, and so on. We have persistence. We are stateful in the stateless world of HTTP.

Of course, sometimes we want to reset out state. What then? Code up a "zap_session" method in the controller:

  def zap_session
session[:f1] = nil
session[:f2] = nil
redirect_to(:action => "index")
end

Most of the preceding is obvious. We set the values of both session keys to nil, which would trigger the index method to set them to 1. The redirect_to method tells what screen to pull up. After all, zap_session has no corresponding view, so without the redirect, a call to zap_session would be greeted with a "missing template" error. The redirect tells it to rerun the index view, which in turn runs the controller's index method, which in turn fills the nil session data with 1, thereby resetting.

Now we need to change the view in order to insert a link that calls zap_session:

<h1>Fibb#index</h1>
<p>Find me in app/views/fibb/index.rhtml</p>
f1=<%= @f1 %><br>
f2=<%= @f2 %><br>
<br>
<%= link_to "Click to reset", :action => "zap_session" %>

The screen now looks like this:


Fibbonacci screen with reset link

Click the link, and you'll see the numbers go back to 1 and 2.

The ability to reset the session is very often a good thing. Sometimes the session variables assume an illegal state, causing the program to do illegal things, including the dreaded blank page.

A Simple Data App

To make your data app you're going to generate a scaffold. Scaffolds are generated code based on database tables. Such autogenerated web pages are not very pretty nor especially convenient, but they're sure fast to create. Once created, you can pretty them up in iterations.

Here are the steps:
  1. Create the app
  2. Edit config/database.yml to give user and password
  3. Create and populate database
  4. Generate a scaffold

Create the app

Get back in the tcrails directory and perform this series of commands:
rails hellodata
cd hellodata
The preceding are the familiar commands to create an app and get to the head of its tree.

Edit config/database.yml to give user and password

Edit config/database.yml to connect the development environment to database using username myuid and password xxx. Failure to perform this step will cause model generation to fail. When you're done editing, the development portion of config/database.yml will look like this:

development:
adapter: mysql
database: hellodata_development
username: myuid
password: xxx
socket: /var/lib/mysql/mysql.sock


The username was originally root, with no password -- an insecure situation. You've changed the username to myuid and given it a password for more security. Obviously you'll use a different password so that script kiddies aware of this tutorial won't access your database.

While you're in there, notice that Rails expects your database to be named hellodata_development. That was generated by the rails hellodata command. Remember that database name, because you'll need it when you create your database.

Create and populate database

Create the following SQL file named load_dogs.sql:

####################################################
# CREATE THE DATABASE
####################################################
drop database if exists hellodata_development;
create database hellodata_development;
use hellodata_development;

####################################################
# REINITIALIZE THE TABLES.
####################################################
drop table if exists dogs;

####################################################
# CREATE THE DOGS TABLE
# FAMILIES IS THE ONE, AND MEMBERS IS THE MANY.
# CREATE UNIQUE INDEX SUCH THAT FAMILY_ID PLUS NAME IN
# MEMBERS IS FORCED TO BE UNIQUE.
####################################################
create table dogs (
id int not null auto_increment,
name varchar(20) not null,
family_name varchar(20) not null,
primary key (id)
);
# show tables;
# describe families;
# describe members;


####################################################
# LOAD dogs
####################################################
insert into dogs (name, family_name) values ('Fluffy', 'Farber');
insert into dogs (name, family_name) values ('Fido', 'Fisher');
insert into dogs (name, family_name) values ('Pirate', 'Peterson');

####################################################
# CREATE USER myuid, GIVE PROPER PRIVILEGES
####################################################
grant select, insert, update, delete, create
on hellodata_development.*
to myuid@localhost identified by 'xxx';

####################################################
# SWITCH TO USER myuid
####################################################

####################################################
# CHECK YOUR WORK
####################################################
select id, family_name, name
from dogs order by family_name;

As you see, the preceding script creates the database, creates the dogs table, inserts some data, creates user myuid with necessary privileges and a password, and then displays the contents of dogs.

Run the preceding file like this:
mysql -u root -p < load_dogs.sql
Use the mysql program to verify you can access the table as user myuid. Remember, you modified config/database.yml so that Rails uses user mysql to connect to the database, and that config/database.yml calls for a database named hellodata_development.

Generate a scaffold

When you generate a scaffold, you generate a simple web app with screens to list out a data table, and to provide create, edit and delete facilities.

When you generate a scaffold, you name the model as the titlecase singular of the table, which should be named as a plural. In this case we call our model Dog, because we already named our data table dogs. When creating a scaffold, it's important to remember that the generator reads the database, and builds the application to match the database. That's why we built the dogs table before generating the model. Now let's generate the model...

Perform the following command:
ruby script/generate scaffold Dog Doglist
In the preceding command, we use the generate script to create a scaffold, which is a controller and a series of views to manipulate data. Here's the explanation of the command:

ruby script/generate scaffold Dog Doglist
ruby script/generate  
Rails' generate script
scaffold
You're generating a scaffold. A scaffold is a very simple Add/Change/Delete set of views.
Dog
The name of the model you're creating. Rails' default naming conventions dictate that the name of the model is the singular of the the name of the data table, which is why we called it Dog instead of Dogs. The scaffold generator sees the model named  Dog, makes it plural, and looks for a data table named dogs, which it finds because you created it.

BE SURE THE MODEL NAME IS SINGULAR!
Doglist
The name of the controller. Generating a model also generates a controller. In this case we ask the generator to call the model Doglist.


Now use a browser to check the following URLs:
The first URL should show the state of Rails. The other one shows a list of all the rows in the dogs database. Each row has links to edit or destroy (delete) the row. At the bottom of the list is a link to create a new row. Although formatted in an ugly way, this is a full web app for manipulation of a single table.

To gain a better understanding of the generated code, and Rails in general, view the created files:
vi -R app/controllers/doglist_controller.rb app/views/doglist/list.rhtml app/views/doglist/edit.rhtml app/views/doglist/new.rhtml
I like scaffolds. In less than 5 minutes you can generate a barebones app that works. From there, you can modify the controller, model and views to achieve exactly what you want, in small iterations, knowing you can drop back to the previous iteration if necessary. Even though the scaffold doesn't give you what you want, it gives you a working prototype in less than 5 minutes. Unless you've memorized all Rails syntax for controllers, models and views, this is five minutes very well spent.

This exercise showed generation of a scaffold for a single table, but it can be done for much more complex data setups (schemas).

Ajax

Ajax stands for Asynchronous JavaScript And XML. It's a technology by which browser and the web server can communicate without changing the web page. This saves bandwidth when you update small portions of large web pages. It enables field level validation instead of the form level validation we've had to endure since the start of the web app era.

Ajax isn't perfect. It can get somewhat complicated, and although right now it seems to act identically on major modern browsers, that can change as soon as one browser company decides they can profit from the others not rendering the same way.

The good thing about Rails is Rails comes with Ajax support, such that implementing Ajax is easy. In this article you'll build a small Ajax app.

The hallmark of Ajax is that the screen changes without refreshing the web page. Any demonstration app would need to prove that the web page is not refreshing. For this, we turn to our old friend, the Fibbonacci numbers. You'll program an app with two sets of Fibbonacci numbers -- one that increments only when the browser is refreshed, and one that is refreshed only when the "Next AJAX Fibbonacci Number" link is clicked. If each can increment without incrementing the other, you've proven your point.


To accomplish this you'll create a new app called ajax. Start by creating an app with a controller called Fibb and views called index and changepart:
rails ajax
cd ajax
ruby script/generate controller Fibb index changepart
You'll be working with three files created in the preceding commands:
  1. app/controllers/fibb_controller.rb
  2. app/views/fibb/index.rhtml
  3. app/views/fibb/changepart.rhtml
There are many forms of Ajax. One simple one is to have the contents of a <div></div> section replaced by the contents of a different view. That's what you'll do.  The different view is changepart.rhtml. Let's start with app/views/fibb/changepart.rhtml:
F1=<%= session[:fa1] %>, F2=<%= session[:fa2]%>

Nothing could be clearer. The preceding displays two session variables called fa1 and fa2. Those two session variables must be set in app/controllers/fibb_controller.rb. However, the preceding rhtml file is never displayed in a browser. Instead, it's displayed as a replacement for a <div></div> section of app/views/fibb/index.rhtml, as shown below. Code of special interest is colored, and will be explained after the code display:
<head>
<%= javascript_include_tag "prototype" %>
</head>

<body>

<p>
<center><b><big><big><big>
Normal and Fibbonacci Numbers
</big></big></big></b></center>
</p>

<p><center>Refresh browser to increment normal Fibbonacci numbers.</center></p>

<table border="1" cellpadding="8" width="80%">
<tr>
<td><b>NORMAL</b></td>
<td><b>AJAX</b></td>
</tr>
<tr>
<td>F1=<%= session[:f1] %>, F2=<%= session[:f2] %></td>
<td>
<div id=div_to_replace>
F1=<%= session[:fa1] %>, F2=<%= session[:fa2] %>
</div>
</td>
</tr>
</table>

<p>
<%= link_to_remote("Next AJAX Fibbonacci Number",
:update => 'div_to_replace',
:url => { :action => :changepart }) %>
(Increment Ajax Fibbonacci numbers)

</p>

<p>
<%=link_to_remote("Clear all variables",
:url => { :action => :clear_all_vars}) %>
(You must refresh the browser to see the result)
</p>

</body>

Exercise your new app

Now that you've created this app, you can exercise it to prove to yourself that AJAX can update the screen without refreshing. However, keep in mind that this is a barebones example with no error handling or even handling of special circumstances. It typically won't work right the first few clicks of the AJAX link and the first few refreshes. This is especially the true the first time, because you have no cookies for this app. As mentioned, for simplicity clearing all variables does not refresh the AJAX variable display on the screen after clearing all variables.

Nevertheless, you can plainly see that when you click the AJAX link, the AJAX display increments but the display incremented by refreshing does not, clearly proving that you updated web content without refreshing the page.

Using (or not) AJAX

This article barely scratches the surface of AJAX's capabilities and costs. AJAX can do all sorts of sub-communication between server and brower, and in doing so can get you in trouble if you're not careful.

Is AJAX the next miracle drug, or a side effect ridden disaster waiting to happen? It's both. Like a drug, it should be used only in certain circumstances, and then it should be used "as prescribed".

With infinite bandwidth AJAX would be totally unnecessary. With infinite bandwidth (and infinite server speed) you could update the tiniest part of the screen by refreshing the whole page, and never see a flicker.

That will never happen. Even if bandwidth increases by a factor of 1000, we humans will find ways to consume it all and still feel the need for more. Bandwidth will always be a limitation. Therefore, there will always be a desire to refresh a small part of the screen.

Potential uses abound. With AJAX, field level validation becomes possible. When web apps came out, we were forced to forego the field level validation we'd become accustomed to, and retreat to the stone age of form level validation, in which you need to complete the entire form before being informed of errors.

You can use AJAX to implement click and drag on a web page. You could use it to implement a simple game or puzzle. Imagine how much nicer a web based chess game would be if the screen needn't refresh to move one piece.

There are countless applications that benefit from updating only the part of the web page that's actually being changed.

Before you make every app an AJAX app, consider its costs. Like a drug, it has side effects. When you use AJAX in any substantial way, you can kiss your browser's back button goodbye. The back button will send you back, but not to where you might expect. From what I hear, this can be overcome by proper coding. A LOT of proper coding.

Then there's the Javascript connection. AJAX depends on Javascript. If you're anything like me, Javascript makes you nervous. It's fairly consistent across browsers today, but there are no guarantees. Perhaps there will come a time when a company with dominant market share will make their version of Javascript incompatible with the rest in order to force users of other browsers to switch to the dominant one. Even if that doesn't happen, Javascript interspersed with HTML is usually an ugly devil hard to maintain.

The bottom line: If AJAX will solve a significant problem for you, and if you can live with its side effects and disadvantages, go for it. Otherwise, consider other alternatives, such as regular web apps or Java applets.

============================================================

x

x

x

x

x

x



x

x



x

x



x

x



x

x



x

x



x

x




Troubleshooters.ComCode Corner * Linux Library