Sunday, May 31, 2009

Ramaze, jQuery, and Ajax

This post tries to show how to use Ajax and jQuery with Ramaze. Since, as usual, I didn't really know anything about JavaScript, jQuery, or Ajax, this was quite a learning experience. Right up front, I need to thank the Ramaze email list is general and Gavin in particular for patiently answering my questions. The exchange that started this is documented here.

Also, this jQuery tutorial, provided me a convenient jumping off point and much of the code for the jQuery is taken directly from here or is based on this code and slightly modified.

What we're going to do in this example is some very simple Ajax which put up five numbers, let's you select one, and then prints the number you selected below along with the time you selected it at. You probably wouldn't normally do this with Ajax, but it does show how to use it.

Here's our start.rb file:


# start.rb

require 'rubygems'
require 'ramaze'

# You can access it now with http://localhost:7000/
class MainController < Ramaze::Controller

# Layout using page but not if it comes from an Ajax request.
layout(:page){ !request.xhr? }

def index
@title = "Ramaze / Ajax Example"
end

# This should only get called from an ajax request.
def choose
if request.xhr? # came from ajax request
# Create a JSON "object" of the choice that can in through the post
# request and the current time. For the time, we need to enclose it
# in double quotes so that it will be interpreted as a string.
"{ choice: #{request['choice']}, time: \"#{Time.now}\" }"
else
request['choice'].to_s
end
end
end

Ramaze.start



It's pretty straightforward but does have a couple of new items in it. First there's this:

layout(:page){ !request.xhr? }

This tells Ramaze to use page for layout accept in the case of an Ajax call. When you make an Ajax call, you want just the data returned (in our case some JSON) and not the entire formatted page. This took the help of the Ramaze email group (thanks Gavin!) to figure out. If you're searching you may find deny_layout. This has been removed in the latest Ramaze, so avoid it.

Our index method is very straightforward so we'll move on to the choice method. Here, we simply take in the data from the post in this case something that will look like {choice: 2} and create another JSON object that also contains the time from a Time.now call. Here, we need to enclose the time in double quotes, so that it will be interpreted as a string. Without the quotes, there is no way to interpret it correctly.

Our index.xhtml file is very simple


<!-- view/index.xhtml -->

<h2>#@title</h2>

<p>This example demonstrates the use of Ramaze and Ajax along with some JQuery and JSON.</p>

<!-- An empty container where we'll put the choices and the return values
values from the ajax/post call.
-->

<div id="ajaxContainer"></div>


The only interesting piece is the empty div element. We're going to put our ajax code into it via page.xhtml.

Finally, here's the page.xhtml


<!-- view/page.xhtml -->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>#@title</title>
<link rel="stylesheet" type="text/css" href="/page.css"/>

<!-- Our jQuery is in the public/js directory -->
<script src="js/jquery-1.3.2.js" type="text/javascript"></script>

<script type="text/javascript">

// For jQuery put everything inside of the document ready code.
$(document).ready(function() {

// Create an array of text and links. We'll add this to the
// ajaxContainer using join()
var choiceMarkup = ["Please choose a number: "];
for(var i=1; i <= 5; i++) {
choiceMarkup[choiceMarkup.length] = "<a href='#'>" + i + "</a> ";
}
choiceMarkup[choiceMarkup.length] = (" Your choice will be printed below.");

// Grab the ajaxContainer so we can add the choiceMarkup to it.
var container = $("#ajaxContainer");

// Add markup to container
container.html(choiceMarkup.join(''));

// Add click handlers. Here we're going to get all of the anchor elements <a>
// and add the function to them.
container.find("a").click(function(e) {

// Don
't do the normal thing you'd do when clicking a link.
e.preventDefault();

// Send a post request to the choose method when a link is
// clicked. Pass in the JSON "choice: item" to the function.
// The callback routine gets a resultObject(JSON) and a status
// (not used and not actually returned). The choose() method
// will return JSON, the fourth parameter, to post.
$.post(
"/choose",
{choice: $(this).html()},
function(resultObject, resultStatus) {

// Take the resultObject and grab the choice and time from it and format it.
var result = [
"<br>Thanks for choosing. You chose: ", resultObject.choice, " at ", resultObject.time
];
// Add the result to the ajaxContainer at the bottom. This will create a new
// item each time one of the numbers is clicked.
$("#ajaxContainer").append(result.join(
''));
},
'json' );
});
});
</script>
</head>
<body>
<div id="header">
<h1>SteamCode</h1>
</div>
#@content
<!-- Set the footer in the center of the screen. -->
<div id="footer" style="text-align: center;">
<h5> Powered by Ramaze </h5>
</div>
</body>
</html>



The first new thing we see here is the inclusion of the jQuery library. I've put it into the public/js directory. If you use a different version other than 1.3.2 you will need to change this line. Next is our actual script. All jQuery code is put inside the document ready block. After that, we create some text, links for the five choices, and a bit more text and shove these into an array, choiceMarkup. Then we grab the ajaxContainer defined in our view/index.xhtml file and put the choiceMarkup into it.

Next up, we find all of the anchor, a, links and add a function to them when they're clicked. The first thing we do in this function is disable the normal response to a click and then add our own code. Here we do a post function, calling the choose method in our controller and pass JSON that looks like {choice: 3} (we talked about this above). When the function returns, we have our data in the result object and as also discussed, this contains the choice and the time. We format this and then add it to our ajaxContainer. This will add a new line each time something is clicked and continue until we do a refresh. The final parameter to the post is the 'json' which tells jQuery that the data returned will be (obviously) JSON.

Everything else we've seen before and I won't go over it again.

There's quite a few new things to see in here and there aren't too many examples on the web showing the use of Ajax, jQuery, and Ramaze. Here's a post, but I'm not sure that it will work with the new Ramaze. It may take some modifications to get it working. Here's a nice jQuery link that helped a bit. Finally, for JSON, try here. JSON is not complex, but you do have to follow the rules (I didn't originally and it took a while and some help to figure out).

Let me know of any questions or comments.

Friday, May 22, 2009

Templates, Sequel, and Ramaze (Redux)

After I posted this morning, Jeremy Evans of Sequel fame pointed out a few issues. First he suggested that instead of using datasets in the controller as I had done, that I use the Model instead and showed me how to do it. Second, he suggested that instead of using the User.find(id) in the personal(id) method, I use instead User[id] as more idiomatic. Finally, in the view/index.xhtml view, he noted that Rs has been deprecated in favor of r. So with that, here's the three new files (I neglected to post the models/user.rb earlier anyway).

Here's the new 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 user's ids and names from the User model. We're going
# to display all of them on the index/home page.
@users = User.id_and_names
@title = "Welcome to SteamCode"
end

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

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


Here's the new view/index.xhtml


<!-- view/index.xhtml -->
<h2> Users <h2>
<ul>
<!-- 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="#{r(:personal)}/#{user[:id]}">#{user[:first_name].capitalize} #{user[:last_name].capitalize}</a> </li>
<?r end ?>
</ul>


And finally here's the models/user.rb (not posted earlier)


# models/user.rb
#
# This is the model for the User and is backed by the :users table in the
# database. We add the id_and_names for the index method in the
# main_controller.
require 'rubygems'
require 'sequel'

# Create the Account model.
class User < Sequel::Model

# Create a class method to grab the id, and first and last names from
# the default User dataset.
def self.id_and_names
select(:id, :first_name, :last_name).all
end
end


If you have questions or comments on this or the previous post (or any post for that matter), please don't hesitate to ask.

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 Class.new 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.
Class.new(Sequel::Migration) do
def up
create_table(:users) do
primary_key :id
String :first_name
String :last_name
String :user_name
Integer :age
end

# 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')
end

def down
drop_table(:users)
end
end



The first thing to notice is that we don't name the class here, we use Class.new(Sequel::Migration). 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.
Ramaze.start



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"
end

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"
end
end



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>
<ul>
<!-- 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 ?>
</ul>


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

Tuesday, April 21, 2009

Registering Users and More

For this post we start with the post Using Ramaze and Sequel Together code and add in Registration for users. We're also going to add in a couple of more things along the way which is not in keeping with my normal way of doing things, but in this case they're pretty simple. Quite a lot of this post, I realized while working on it, was developed using things I learned from RailsSpace and the associated book. If you're interested in learning Rails at all, you should check this out. I had much more success with it than with the Agile Web Development With Rails (YMMV). Anyway, along with the Registration page, we're going to add in a place holder for About and Help pages along with a Logout page. We're also going to be doing a bit of CSS (mostly Cargo Culting from the RailsSpace book).

Here's our first database migration from dbMigration

# dbMigration/001_LoginMigration.rb
# Run:
# sequel -m dbMigration -M 1 sqlite://accounts.db
# from the top level directory to create the :accounts table with login and
# password columns.
#
class CreateAccountsTable < Sequel::Migration

# For the up we want to create the account table.
def up
# Create the accounts table with a primary key, a login, and a
# password.
create_table(:accounts) do
primary_key :id
String :login, :unique=>true
String :password
end
end

# For the down we want to remove the accounts tables.
def down
drop_table(:accounts)
end
end



this creates the account table and put in the login and password columns. This code is directly from the post mentioned above. In order to make this a bit more realistic, I've added a second migration:

# dbMigration/002_AddEmailMigration.rb
# Run:
# sequel -m dbMigration -M 2 sqlite://accounts.db
# from the top level directory to add the email column to the accounts table.
#
class AddEmail < Sequel::Migration

# For the up we want to add the email to the accounts table.
def up
alter_table(:accounts) do
add_column(:email, :text)
end
end

# For the down we want to remove the email column.
def down
alter_table(:accounts) do
drop_column(:email)
end
end
end



which takes the existing accounts table and adds in the email column. Just run a sequel -m dbMigration -M 2 sqlite://accounts.db which should run both of the migrations in order giving us the table as well as the three columns.

OK, here's the first bit of real code, our start.rb

# 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("accounts.db")

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

# Start Ramaze.
Ramaze.start



This just opens the database, and once again we're using Sqllite, loads the one controller and then the one model, and finally starts ramaze.

The real work of this program is done in the controller, controllers/main_controller.rb. Here's the listing:

# controllers/main_controller.rb
#
# This example is based on the previous "Using Models" example. It has a
# number of methods . The index method will take data from a form and call the
# Account.find method. If the Account.find method returns something (we aren't
# actually going to use what's returned), we will set the session variable,
# and redirect to the logged_in method. If it returns false we will set the
# flash variable and stay on the index page.
class MainController < Ramaze::Controller
# Use page.xhtml in the view directory for layout
layout :page

# Set up a helper to check if we're logged in and only allow access
# to the :logged_in page if we are. This is probably the hard way to
# do this for only the single page but will make much more sense if
# we add more pages as we'd do in a real application.
helper :aspect
before(:logged_in) {
unless logged_in?
# Set the flash message which will only be available in the next
# screen. In this case that will be the logged_in screen.
flash[:message] = "You must log in before accessing the requested page."
redirect Rs(:index)
end
}

# You can access it now with http://localhost:7000/ This should display a
# welcome message. This is the home page.
def index
@title = "Welcome to SteamCode"
end

# Register a new user with SteamCode. We will get here from the
# views/register.xhtml page where the user will put in their (requested)
# login, password, and email address. First find if the user already
# exists, if it does, then we'll set a message to tell the user so and
# redirect them back to the register screen. If not, we'll go ahead and add
# them to the database with the appropriate login, password, and email
# address. We'll then send them to the login screen to let them log in to
# SteamCode.
def register
@title = "Register with SteamCode"
# Make sure we're getting here from a post request.
if request.post?
# Check the login and password.
# if we find the Account based on the login and password. If we find it
# we'll save the login ID in the session variable and we can use that
# to show if the Account is currently logged in or not. If we can't
# find the Account, we'll set the flash message, set the session to nil
# and just stay on this page.
if Account.find(:login => request[:loginID])

# This user already exists. Set the flash message for them to
# try again.
flash[:message] = "Login #{request[:loginID]} already used. Please select another."

# Stay on the register page.
redirect Rs(:register)
else
# This account does not exist. Grab the loginID, the password,
# and the email and create a new Account with them.
loginID = request[:loginID]
password = request[:password]
email = request[:email]

# Log the new user (a real application wouldn't probably print
# the password out though).
Ramaze::Log.debug "New User Added: loginID = #{loginID} password = #{password} email = #{email}"

# Create the account with the login, password, and email given.
Account.create(:login => loginID, :password => password, :email => email)

# Redirect to the login page.
redirect Rs(:login)
end
end
end

# You can access it now with http://localhost:7000/login
# This should display a form with a login and a password as
# well as a "Login" button in your browser.
def login
# Set the title for the page.
@title = "SteamCode Login"
# Make sure we're getting here from a post request.
if request.post?
# Check the login and password.
# if we find the Account based on the login and password. If we find it
# we'll save the login ID in the session variable and we can use that
# to show if the Account is currently logged in or not. If we can't
# find the Account, we'll set the flash message, set the session to nil
# and just stay on this page.
if Account.find(:login => request[:loginID], :password => request[:pw2])
# Use the name= portion of the input form to grab the data
# from the request variable and save it in the session
# hash table.
session[:loginID] = request[:loginID]

# Redirect to the logged_in screen.
redirect Rs(:logged_in)
else
# The login could not be authorized. Set the flash message
# and stay on this page (index/login). Set the session loginID
# to nil also. This will effectively log the user out. This would
# be reasonable if they are logged in and then try to log in with
# a new login/password.
flash[:message] = "Incorrect password, please try again!!!"
session[:loginID] = nil

# Stay on the login page.
redirect Rs(:login)
end
end
end

# Set the login ID variable so we can issue a welcome message on the
# logged_in page.
def logged_in
@title = "SteamCode Logged In"
@loginID = session[:loginID]
end

# Logout of SteamCode. Sets the session[:loginID] to nil, sets the flash
# message, and goes back to the home page.
def logout
session[:loginID] = nil
flash[:message] = "Thank you for using SteamCode."
redirect Rs(:index)
end

# The about action. Sets the about title. This also uses the view/about
# xhtml file.
def about
@title = "SteamCode About"
end

# The help action. Sets the help title. This also uses
# the view/help xhtml file.
def help
@title = "SteamCode Help"
end

private

# A private helper method that returns true if there is a
# session[:loginID] value set and false otherwise.
def logged_in?
return session[:loginID] != nil
end
end


As normal, we start with a previous post, in this case the Using Ramaze and Sequel Together post. In this case our index page just sets the title "Welcome to SteamCode". The next method is our register which allows us to create a new user (recall in our last version, we just hard coded everything to work with hello/world as a username/password combination). The code here checks the login/password that is passed in from the form and if it already exists, sets a flash message and redirects the user back to the Registration page. Otherwise it will grab the login/password/email from the request hashtable, create a new account, and redirect the user to the login page to allow them to login. One thing to note here is that a couple of people on the Ramaze mail list suggested just creating the account and catching any errors that come back rather than the two piece way of doing things shown here. I kind of like that way, but this seems more intuitive and easier for people just starting out to understand, but note that you may see it done differently in other examples from other people.

The next method is the login and that is very similar to our last example. We simply take the login/password from the request hash and check if they are in the database. If they are, we log the user in and redirect to the logged_in page. Otherwise we add a flash message and redirect back to the login page to allow them to try again. A "real" system would do things like keep count of the number of tries for a login and possibly lock the user out for some time period. Here, once again, we're keeping it simple.

The logged_in method is where the user ends up after a successful login. In most applications, this would be the user's "home" page. Here, set the title and grab the login id so we can greet the user.

Next up is the logout method. This is very simple and sets the user's session[:loginId] to ni, sets a thank you flash message, and finally redirects the user back to the home page.

The next two methods, about and help merely set the title for the two actions.

Finally we have the logged_in? private method which is a helper method which let's us know if the user is logged in to the system or not.

Next up, let's take a look at our model, in models/account.rb.

# models/account.rb
#
# This is the model for the Account and is backed by the :accounts table in the
# database. For this simple example we don't need anything but the definition.
require 'rubygems'
require 'sequel'

# Create the Account model.
class Account < Sequel::Model
end


Once again, as in our previous post, there is really nothing in here except for the Account class being derived from Sequel::Model.

Our view directory has a number of files now corresponding to our new methods from the controller. First our page.xhtml has a few new twists from the previous version.

<!-- view/page.xhtml -->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- Use the page.css in the public directory and set title based on
what's set in the associated method.
-->

<link rel="stylesheet" type="text/css" href="/page.css"/>
<title>#@title</title>
</head>
<div id="header">
<h1>SteamCode</h1>
</div>
<div id="nav">
<!-- Move this next section over to the right side of the screen. It
will contain the Login/Register if we're not logged in and the Logout
if we are. -->

<span style="float: right">
<!-- We're going to use the private method logged_in? here to test if
we want to showhte Login/Register links or the Logout link -->

<?r if !logged_in? ?>
<a href="#{R(MainController, :login)}">Login</a> |
<a href="#{R(MainController, :register)}">Register</a>
<?r else ?>
<a href="#{R(MainController, :logout)}">Logout</a>
<?r end ?>
</span>

<!-- These next three will be on the left side and always there -->
<a href="#{R(MainController, :index)}">Home</a> |
<a href="#{R(MainController, :about)}">About Us</a> |
<a href="#{R(MainController, :help)}">Help</a>
</div>
<body>
<!-- Display the flashbox message -->
#{flashbox}

<!-- Display the actual content. This will come from the method or the
associated view/*.xhtml file
-->

#@content

<!-- Set the footer in the center of the screen. -->
<div id="footer" style="text-align: center;">
<h5> Powered by Ramaze </h5>
</div>
</body>
</html>


First, the head now contains a style sheet, page.css.

/* Header CSS */
#header {
background:#9DA9EE;
color: white;
margin-bottom: 0;
padding: 0.25em;
}

#nav {
background: #ccc;
color: black;
padding: 0.5em;
}

/* Footer CSS */
#footer {
background:#9DA9EE;
color: black;
}

There's not too much in there, just the beginnings of what you would have in a "real" style sheet including styling for the header, footer, and nav.

Next the page.xhtml has the header, now styled a bit, followed by our nav section. Here we use a bit of ruby to decide what to show. If the logged_in? method from the controller is not true, we display the Login and Register links. If it is true, then we display the Logout link. I don't think we've discussed the Ruby aspect of this before. but in our views, we can use the "" and put in any valid ruby code and we have access to methods in the controller as we've used here. After that, we have the three links that are always displayed on the right hand side, index, about, and help. index is our main page and about and help are really just place holders for now. Here's the views for all of the above:

<!-- view/login.xhtml -->
<form id="login" method="post">
<div>
<!-- for= goes with id=, the name= is placed in the request variable. -->
<label for="nick">Login:</label>
<input id="nick" name="loginID" type="text" />
<br/>
<label for="pw1">Password:</label>
<input id="pw1" name="pw2" type="password" />
<br/>
<input type="submit" value="Login" />
</div>
</form>


<!-- view/register.xhtml -->
<form id="register" method="post">
<div>
<!-- for= goes with id=, the name= is placed in the request variable. -->
<label for="loginID">Login:</label>
<input id="loginID" name="loginID" type="text" />
<br/>
<label for="password">Password:</label>
<input id="password" name="password" type="password" />
<br/>
<label for="email">Email:</label>
<input id="email" name="email" type="text" />
<br/>
<input type="submit" value="Register" />
</div>
</form>


The login and register views above both contain forms that the user can fill in and pass to the appropriate methods in the controller and their associated methods were discussed above. For the register, you put in a login, (that's checked in the controller to make sure there's not already a user with that login), a password (no error checking here, so get it right), and an email address (unused through the rest of the system). Obviously, in a real system, you would do things differently. On the login page, the user puts in a login/password pair and the controller authenticates and then logs the user in. Once the user is logged in to the system, they will go to the logged_in page

<!-- view/logged_in.xhtml -->
Welcome to SteamCode: #@loginID


Here they're just shown a welcome message with their user name from the logged_in method in the controller.

Nothing really in the index (the main page), about, or help pages shown here

<!-- view/index.xhtml -->
<h2>This is the Steamcode main page</h2>


<!-- view/help.xhtml -->
<h2>This will contain a FAQ on all of the things you can do with
SteamCode.</h2>


<!-- view/about.xhtml -->
<h2>This will talk all about SteamCode and all of the wonderful things we do.</h2>


So there you have it. If not the beginnings of a web application, at least the beginnings of the beginnings of a web application. As always, let me know if you have any questions or comments and I'll do my best to answer them. Also, if you end up building any Ramaze apps, let me know as I'd love to see what can be done and more importantly how things are done.

Saturday, April 11, 2009

Simple Genetic Algorithm

Edit: Hopefully fixed now.

Edit: Looks like the coloring is whacked out below, but I'm too lazy to clean it up right now. Sorry for the inconvenience.

Sorry for not posting for a bit. I've got a rather large post coming up, but in the meantime, here's a quick one on genetic algorithms (OK, a bit grandiose for what it really is). A couple of weeks ago, I was in Palm Springs with time to kill in the evenings and ran across this post on converting a string using simple mutation and random selection. It took only a short period of time to get the initial version going, and then a few refactorings later, I ended up with this. Getting this ready to publish, I found a few other things that would be nice to put in and better ways to do things, but let's just put it out and you can fix it up (or not) if you like. One thing to warn though there is no error checking on the inputs.

Ok, here's the main program. It reads in the command line arguments and starts everything going.


#!ruby
# == Synopsis
# Runs the weasle program
#
# == Usage
# ruby Weasel.rb [-g generations] [-o number of offspring] [-d desired string]
#
# == Author
# Scott LaBounty
#
# == Copyright
# Copyright(c) 2009 Scott LaBounty
#
#

require 'getoptlong'
require 'rdoc/usage'
require 'population'
require 'organism'

# Set up the command line options
opts = GetoptLong.new(
["--max_generations", "-g", GetoptLong::REQUIRED_ARGUMENT],
["--number_offspring", "-o", GetoptLong::REQUIRED_ARGUMENT],
["--desired_string", "-d", GetoptLong::REQUIRED_ARGUMENT],
["--help", "-h", GetoptLong::NO_ARGUMENT]
)

# Set the default values for the options
max_generations = 5000
number_offspring = 100
desired_string = "methinks it is like a weasel"

# Parse the command line options. If we find one we don't recognize
# an exception will be thrown and we'll rescue with a RDoc::usage
begin
opts.each do | opt, arg|
case opt
when "--max_generations"
max_generations = arg.to_i
when "--number_offspring"
number_offspring = arg.to_i
when "--desired_string"
desired_string = arg
when "--verbose"
RDoc::usage
end
end
rescue
RDoc::usage
end

puts "max_generations = #{max_generations} number_offspring = #{number_offspring} desired_string = #{desired_string}"

# Create the desired organism witht the desired string.
desired_organism = Organism.new(desired_string)

# Create a population with the desired organism, the maximum number of generations, and the number of offspring.
population = Population.new(desired_organism, max_generations, number_offspring)

# Evolve the population
population.evolve



Next up is the population.rb file. It contains the code for evolving the organism and selecting the next generation. It also does the printing out of the current values.

require 'organism'

#
# Population class.
#
class Population

# Initialize with a desired_organism, the maximum number of generations to
# go, and the number of offspring in each generation.
def initialize(desired_organism, max_generations, number_offspring)
@desired_organism = desired_organism
@max_generations = max_generations
@number_offspring = number_offspring
end

# Evolve the population using the desired_organism as a pattern to generate
# the current_organism. Loop generating the number of offspring in each pass
# and pick the best one as the new current_organism. Don't go for more than the
# maximum number of generations.
def evolve
num_generations = 0
current_organism = Organism.new(@desired_organism)
current_organism.randomize
while (current_organism != @desired_organism) && ((num_generations += 1) < @max_generations)

# Create the offspring array and generate the number of offspring
# from the current_organism.
offspring = []
1.upto @number_offspring do
o = Organism.new(current_organism)
o.mutate
offspring << o
end

# Find the best offspring from the ones we
# created above and make it the current offspring.
best_offspring = offspring[0]
best_count = 0
count = 0
offspring.each do | o |
count = o.compare(@desired_organism)
if count >= best_count
best_offspring = o
best_count = count
end
end

# Set the new current_organism to the best_offspring.
current_organism = best_offspring

# Print out the best/current offspring and the matching count to
# see how we're doing.
puts "generation = #{num_generations}: best_offspring = #{best_offspring}: count = #{count}"
end

# Print out the final tally.
puts "Number of generations to result = #{num_generations}"
end
end



Finally, there's the organism itself. We derive from the String class so we can take advantage of the methods already in String.


#
# Organism class that is derived from String. For the alphabet, we use lower case
# letters, and the space only.
class Organism < String

@@alphabet = ["a", "b", "c", "d", "e",
"f", "g", "h", "i", "j",
"k", "l", "m", "n", "o",
"p", "q", "r", "s", "t",
"u", "v", "w", "x", "y","z", " "]

# Completely randomize the string.
def randomize
0.upto length-1 do |i|
self[i] = @@alphabet[rand(27)]
end
end

# Replace a single character in the string with
# a new one from the alphabet. We could turn this into a one-liner,
# but the multiple lines help with readability.
def mutate
replace_position = rand(self.length)
replace_value = @@alphabet[rand(27)]
self[replace_position] = replace_value
end

# Compart the two strings and return the
# number of positions that match.
def compare(d)
count = 0
0.upto d.length-1 do | i |
if d[i] == self[i] then
count = count + 1
end
end
return count
end
end


So there you go. Probably the simplest genetic program you could possibly write. As noted above, there's no error checking so be careful with the input strings. The easiest thing here would be to convert the string to lower case and remove everything else but spaces. The other big problem is that the code is more Java/C++ like than it is Ruby like. Mostly this is a reflection of my background and I'd be very interested in ways you have to make it more Ruby like.

Leave any questions or notes in the comments as usual.