Friday, May 22, 2009

Templates, Sequel, and Ramaze

Well, after the last really large post, I thought that I'd work on something a bit more manageable for this one. There are three new things in this post, some with Sequel, some with Ramaze, and we'll take a look at a slightly more interesting use of templates (really only slightly though). Let's start with our migration:

# This is the "new" way to do migrations by using the form. 
# It means that a new class name is not required and so there is no chance
# of creating a second class in the migration files that is the same as the
# first causing problems. do
def up
create_table(:users) do
primary_key :id
String :first_name
String :last_name
String :user_name
Integer :age

# Here we're going to go ahead and add a couple of users in the migration. This saves us from having
# to add them via forms are similar.
from(:users).insert(:first_name => 'john', :last_name => 'smith', :user_name => 'jsmith', :age => '22')
from(:users).insert(:first_name => 'jane', :last_name => 'johnson', :user_name => 'jjohnson', :age => '33')

def down

The first thing to notice is that we don't name the class here, we use This was recommended by Jeremy on the Sequel list and it means that there won't be any issues if you accidentally reuse a class name in multiple migrations. There's nothing new in the creation of the table, but right after that we go ahead and add some data. This probably isn't a great idea for a normal application, but for our simple demonstration, it simplifies things. Here what it means is that we can add a couple of users without all of the machinery from the last post on registering users. Finally, we have the down() method which drops the table. To generate the table run:
sequel -m dbMigration/ -M 1 sqlite://users.db which will create the users.db sqlite database with the defined users table and the two rows we defined.

Next we have the start.rb file:

# start.rb
# This is the main program for the example. It loads the Sequel database,
# loads the controller and model, and then starts up Ramaze.
# You can add new accounts on the registration page.
require 'rubygems'
require 'ramaze'
require 'sequel'

# The database should have been set up using the database migrations (there are
# currently two of them) in the dbMigration directory. Run them with:
# sequel -m dbMigration -M 2 sqlite://accounts.db
# Open the accounts database. This must be done before we access the models
# that use it.
DB = Sequel.sqlite("users.db")

# Load the controllers and models (one of each in this case).
require 'controllers/main_controller'
require 'models/users'

# Start Ramaze.

Nothing too much interesting in here, just the normal includes, grabbing the database, models, and controllers, and then starting up ramaze.

Our first "interesting" code is in controllers/main_controller.rb.

# controllers/main_controller.rb
class MainController < Ramaze::Controller
# Use page.xhtml in the view directory for layout
layout :page

# You can access it now with http://localhost:7000/ This should display a
# welcome message. This is the home page.
def index
# Get all of the users from the database. We're going to display
# all of them on teh index/home page.
@users = DB[:users].select(:first_name, :last_name, :id)
@title = "Welcome to SteamCode"

def personal(id)
# Find the user with the given id. This will come from the link created on the
# index/home page.
@user = User.find(:id => id)

# Create the title with first name / last name 's Home Page.
@title = "#{@user[:first_name].capitalize} #{@user[:last_name].capitalize}'s Home Page"

We have our normal layout using view/page.xhtml. Then there is the index() method. Here we're going to grab all of the users from the database DB[:users] giving us a dataset and then we're going to get only three of the four columns using the select(:first_name, :last_name, :id). In a normal application, we'd have many more than four columns, so grabbing just the ones you need make a bit more sense than it might appear here. Given what we've put into the database in our migration, we know we should have the ids, first name, and last name of the two users and we're going to store them in @users which will then be available in our view. Next we just go ahead and set the @title for the page.

Here's the view that uses this:

<!-- view/index.xhtml -->
<h2> Users <h2>
<!-- Loop through each of the users (from MainController/index and
Create a link from MainController/personal and the "id" of the user.
This will then call MainController/personal/id and the id will be used
as a parameter to personal. This in turn will allow us to find the user
and go to their "home" page. The "angle bracket question mark r" are
used to put ruby code inside the template and any valid ruby code can
go here.

<?r @users.each do | user | ?>
<li> <a href="#{Rs(:personal)}/#{user[:id]}">#{user[:first_name].capitalize} #{user[:last_name].capitalize}</a> </li>
<?r end ?>

We start with the header and then next we create a list with the ul element. Next is the templating. We have a:
<?r @users.each do | user | ?&gt.

This is really just ruby code that's going to loop through each of the users that we created in the controller. The next line is a bit complex, although there's still no magic:
<li> <a href="#{Rs(:personal)}/#{user[:id]}">#{user[:first_name].capitalize} #{user[:last_name].capitalize}</a> </li>

We're going to create a link here that looks like personal/id. Remember that one of the columns we added to user was the id. Next we're going to make the text of the link the first name and last name and we're going to capitalize them to make them look nicer in case they weren't input this way (which we didn't in the migration).

Finally, we have:
<?r end ?>

which ends the each we started above. What all of this does is create a list of links to the personal page of each user using their name as the text.

Let's go back now to the personal(id) method in the main_controller. The first thing to notice is that we have a paramter on the method and that this is the first time we've seen that on a controller method. Basically, if we have a method x in a controller and we have a url that looks like http://localhost:70000/x/y/z, then y and z are passed to the x method as parameters. Here we're going to use the id to grab the correct user via the User.find() method, and generate a "home" page for them.

Here's the view/personal.xhtml file

<!-- view/personal.xhtml -->
<!-- Just create a headline with the user's first and last name plus Home Page
and then their "personal" data. In this case just their age.

<h2> #{@user.first_name.capitalize} #{@user.last_name.capitalize}'s Home Page <h2>
#{@user.first_name.capitalize} is #{@user.age} years old.

Once again, this is pretty simple. We just grab variables from the @user (note this is not the same user variable as in the view/index.xhtml file. The latter was a local variable for the loop, the one here is from the personal method.

The view/page.xhtml and public/page.css are the same as our last post

No comments:

Post a Comment