JRuby on Rails Basics

Brian Leonard, Sang Shin, Sun Microsystems, www.javapassion.com/j2ee

 

Rails is a web application and persistence framework that includes everything needed to create database-backed web applications according to the Model-View-Control design pattern. This pattern splits the view (also called the presentation) into "dumb" templates that are primarily responsible for inserting pre-built data in between HTML tags. The model contains the "smart" domain objects (such as Account, Product, Person, Post) that holds all the business logic and knows how to persist themselves to a database. The controller handles the incoming requests (such as Save New Account, Update Product, Show Post) by manipulating the model and directing data to the view.

In Rails, the model is handled by what is called an object-relational mapping layer entitled Active Record. This layer allows you to present the data from database rows as objects and embellish these data objects with business logic methods. You can read more about Active Record in files/vendor/rails/activerecord/README.html.

The controller and view are handled by the Action Pack, which handles both layers by its two parts: Action View and Action Controller. These two layers are bundled in a single package due to their heavy interdependence. This is unlike the relationship between the Active Record and Action Pack that is much more separate. Each of these packages can be used independently outside of Rails. You can read more about Action Pack in files/vendor/rails/actionpack/README.html.

In this lab, you are going to build a simple Rails application as the first exercise step by step. In this exercise, you use the Ruby on Rails support in the NetBeans IDE to create and run a simple CRUD web application called RubyWebLog.  Even though this is a very simple application, you will get an exposure to the the whole development cycle of building a Rails application including the creation of the model, a controller, and a view.  In the 2nd exercise, you will get an exposure to more advanced features of Rails.  It is not required for you to do the second exercise in order to do the homework.


Expected duration: 90 minutes (excluding homework)



Software Needed

Before you begin, you need to install the following software on your computer. 


OS platforms you can use

Change Log



Lab Exercises


Exercise 1: Build and run "RubyWebLog" sample application


In this exercise, you use the Ruby on Rails support in the NetBeans IDE to create and run a simple web application called RubyWebLog.  Even though this is a very simple application, you will get an exposure to the the whole development cycle of building a Rails application including the creation of the model, a controller, and a view.

Acknowledgment: This exercise is based on "Creating a Ruby Weblog in 10 minutes" tutorial contributed by Brian Leonard, maintained by Gail Chappell.

  1. Start MySQL database server and create a database
  2. Create Ruby on Rails project
  3. Create a Model
  4. Migrate database
  5. Create a Controller
  6. Set URL routing
  7. Build and run the application
  8. Add another field

(1.1) Start MySQL database server and create a database


1. Install MySQL database server (if you have not done so yet.)
2. Start the MySQL database server.  (You can start the MySQL server in a different way from the way described below.)


Figure-1.11: Start MySQL database server

2. Create a database.

Figure-1.12: Create a database

                                                                                                                   return to top of exercise


(1.2) Create Ruby on Rails NetBeans project


1. Create Ruby on Rails NetBeans project.

Figure-1.21: Create a new NetBeans project

Figure-1.22: Create Ruby on Rails Application project

2. Give project a name.


Figure-1.23: Give a name to a project

3. Observe that the IDE creates various directories.  (Figure-1.24 below)


Figure-1.24: Observe the directories that are created by the IDE

<Study point: Directory structure of a Rails application>

The directory structure of a Rails application looks as following.  Please note that NetBeans uses logical names to reflect these directories. For example, the Controllers node represents app/controllers directory while Models node represents app/models.  If you click Files view of the project, you will see the directories mentioned below.

app
Holds all the code that's specific to this particular application.
app/controllers
Holds controllers that should be named like weblogs_controller.rb for automated URL mapping.
All controllers should descend from ApplicationController which itself descends from ActionController::Base.
app/models
Holds models that should be named like post.rb.
Most models will descend from ActiveRecord::Base.
app/views
Holds the template files for the view that should be named like weblogs/index.rhtml for the WeblogsController#index action.
app/views/layouts
Holds the template files for layouts to be used with views.
This models the common header/footer method of wrapping views. In your views, define a layout using the
  <tt>layout :default</tt> and create a file named default.rhtml. Inside default.rhtml, call <% yield %> to render the view using this layout.
app/helpers
Holds view helpers that should be named like weblogs_helper.rb. These are generated for you automatically when using script/generate for controllers. Helpers can be used to wrap functionality for your views into methods.
config
Configuration files for the Rails environment, the routing map, the database, and other dependencies.
components
Self-contained mini-applications that can bundle together controllers, models, and views.
db
Contains the database schema in schema.rb. 
db/migrate
Contains all the sequence of Migrations for your schema.
doc
This directory is where your application documentation will be stored when generated using <tt>rake doc:app</tt>
lib
Application specific libraries. Basically, any kind of custom code that doesn't belong under controllers, models, or helpers. This directory is in the load path.
public
The directory available for the web server.
Contains subdirectories for images, stylesheets, and javascripts.
Also contains the dispatchers and the default HTML files.
This should be set as the DOCUMENT_ROOT of your web server.
script
Helper scripts for automation and generation.
test
Unit and functional tests along with fixtures. When using the script/generate scripts, template test files will be generated for you and placed in this directory.
vendor
External libraries that the application depends on. Also includes the plugins subdirectory.
This directory is in the load path.
Directories that are created for the Ruby on Rails project

                                                                                                                   return to top of exercise


(1.3) Create Model


In this step, you are going to use the Rails Generator to create a model for the application. The RubyWebLog application requires a Post model for storing instances of blog posts.

<Study point: What is Model?>

Model-view-controller (MVC) is an architectural pattern used in software engineering. In complex computer applications that present a large amount of data to the user, a developer often wishes to separate data (model) and user interface (view) concerns, so that changes to the user interface will not affect data handling, and that the data can be reorganized without changing the user interface. The model-view-controller solves this problem by decoupling data access and business logic from data presentation and user interaction, by introducing an intermediate component: the controller.

<Study point: What is a Generator?>

Rails' use of runtime reflection and metaprogramming eliminates much of the boilerplate code that you would otherwise have to create. You can often avoid what little boilerplate code remains by using the built-in generator scripts of Rails to create it for you. This leaves you with more time to concentrate on the code that really matters--your business logic.


1. Generate a Model.

Figure-1.31: Generate a model

Figure-1.32: Rails generator

Figure-1.33: post.rb

                                                                                                                   return to top of exercise


(1.4) Migrate the database


<Study point: What is a migration?> 

Migrations can manage the evolution of a schema used by several physical databases. It's a solution to the common problem of adding a field to make a new feature work in your local database, but being unsure of how to push that change to other developers and to the production server. With migrations, you can describe the transformations in self-contained classes that can be checked into version control systems and executed against another database that might be one, two, or five versions behind.  A simple migration example looks as following:

  class AddSsl < ActiveRecord::Migration
    def self.up
      add_column :accounts, :ssl_enabled, :boolean, :default => 1
    end

    def self.down
      remove_column :accounts, :ssl_enabled
    end
  end

The migration example above will add a column called ssl_enabled to the accounts table and remove it again, if you‘re backing out of the migration. It shows how all migrations have two class methods up and down that describes the transformations required to implement or remove the migration. These methods can consist of both the migration specific methods, like add_column and remove_column, but may also contain regular Ruby code for generating data needed for the transformations. (Quoted from ActiveRecord:Migration section of api.rubonrails.org)

1. In the Output window of the IDE, click the link for the db/migrate/001_create_posts.rb file.  The file opens to show the self.up method, which creates a table called posts, and the self.down method, which tears the posts table down. (Figure-1.41 below)


Figure-1.41: Migration

2. Add the title column (shown in bold and blue-colored font) to create_table  in the self.up  method as shown in the Code-1.42 below.

class CreatePosts < ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.column "title", :string
    end
  end

  def self.down
    drop_table :posts
  end
end
Code-1.42: Modified migration file

<Study point: What is ActiveRecord?> 

ActiveRecord is the object-relational mapping (ORM) layer that connects business objects (models) to database tables. It is an implementation of the Active Record pattern described by Martin Fowler.


3.  Click Save All icon. (Figure-1.43 below)


Figure-1.43: Add a column

4. Right-click the RubyWebLog project node and choose Migrate Database > To Current Version.  (Figure-1.44 below) This action updates the the database to include the posts table.


Figure-1.44: Migrate database to the current version

5. Observe that the Output window indicates when the migration is complete. (Figure-1.45 below)


Figure-1.45: Migration

                                                                                                                   return to top of exercise


(1.5) Create a Controller


In this step, you are going to use the Rails Generator to create a controller to interact with the model.  Also, you are going to add scaffolding code, which provides a simple CRUD interface for creating, reading, updating, and deleting entries in the blog.

<Study point: What is an Action Controller?>

Action Controllers are the core of a web request in Rails. They are made up of one or more actions that are executed on request and then either render a template or redirect to another action. An action is defined as a public method on the controller, which will automatically be made accessible to the web-server through Rails Routes.

A sample controller could look like the one below.  There are two actions defined - index and sign.

  class GuestBookController < ActionController::Base
    def index
      @entries = Entry.find(:all)
    end

    def sign
      Entry.create(params[:entry])
      redirect_to :action => "index"
    end
  end

Actions, by default, render a template in the app/views directory corresponding to the name of the controller and action after executing code in the action. For example, the index action of the GuestBookController would render the template app/views/guestbook/index.rhtml by default after populating the @entries instance variable.

Unlike index, the sign action will not render a template. After performing its main purpose (creating a new entry in the guest book), it initiates a redirect instead. This redirect works by returning an external "302 Moved" HTTP response that takes the user to the index action.

The index and sign represent the two basic action archetypes used in Action Controllers: Get-and-show and do-and-redirect. Most actions are variations of these themes.

1. Right-click the Controllers node and choose Generate. (Figure-1.51 below)


Figure-1.51: Generate a controller

2. In the Rails Generator dialog box, type Blog in the Name field. Leave the Views field blank. Click OK. (Figure-1.52 below)  This action creates the blog_controller.rb file and opens the file in the editing area.


Figure-1.52: Create a controller

3. Observe that the  blog_controller.rb node is added under the Controllers node in the Projects window. (Figure-1.53 below)


Figure-1.53: Result of creating a controller

4. Add scaffolding code.
class BlogController < ApplicationController
  scaffold :post
end
Code-1.55: Add scaffolding

Figure-1.56: Scaffolding is added

<Study point: What is Scaffolding?>

Rails can automatically create a full set of CRUD (Create, Retrieve, Update, and Delete) operations and views on any database table. This scaffolding can get you up and running quickly with manipulating your database tables. Over time, you can incrementally replace the generated CRUD operations and views with your own--presumably much prettier and more functional.

                                                                                                                   return to top of exercise


(1.6) Set the URL routing


<Study point: URL routing> 

The default Rails mapping of URLs to controller actions is very simple and easy to understand. Rails tries very hard to present the user with pretty URLs. Rails URLs are simple and straightforward, not long and cryptic. Even so, you can still customize your URLs by using the Rails routing facility. Rails' URL routing is flexible enough to allow you to create virtually any URL mapping scheme. The Rails routing facility is pure Ruby code that even allows you to use regular expressions. Because Rails does not use the web server's URL mapping, your custom URL mapping will work the same on every web server. 

1.  Add a URL routing.

Figure-1.61: A new route

Figure-1.62: Delete index.html

Figure-1.63: Confirmation dialog box

Figure1.64: Save all

                                                                                                                   return to top of exercise

(1.7) Build and run the application


1. Run the application.


Figure-1.71: Run Main Project

Figure-1.72: Seect Main project

Figure-1.73: Running the application - Listing posts

Figure-1.74: New post

Figure-1.75: Listing posts

Figure-1.76: URL's

                                                                                                                   return to top of exercise

(1.8) Add another field


In this step, you are going to add another field so that, in addition to the Title field, the posts table includes a Body field for providing the text of the blog.

1. Generate Database migration.

Figure-1.81: Generate  a new migration

Figure-1.82: Generate migration

Figure-1.83: 002_add_body.rb created

2.  Modify migration file.
class AddBody < ActiveRecord::Migration
  def self.up
    add_column 'posts', 'body', :text
  end

  def self.down
    remove_column 'posts', :body
  end
end
Code-1.84: Modified migration

Figure-1.85: New migration file

Figure-1.86: Migrate database

Figure-1.87: Result of migation

3.  Refresh the browser.

Figure-1.88: Body column is now displayed

Figure-1.89: New post

Figure-1.90: New post is displayed

                                                                                                                   return to top of exercise

Solution


The solution of this exercise is provided as a ready-to-build NetBeans project -  <LAB_UNZIP_DIR>/jrubyrailsbasics/samples/RubyWebLog.  You should be able to build and run the project.

Summary


In this exercise, you have learned how to build a simple Rails application going through the development steps of creating model. controller, and view.  You also learned how to migrate a database.


Exercise 2: Build and run "Flickr" sample application (Optional)


In this exercise, you will  get an exposure to more advanced features of JRuby on Rails.  This exercise is based on the Putting Filckr on Rails tutorial contributed by Brian Leonard.   This exercise requires direct connection to the Internet and does not work if you are working behind a proxy.   This is an optional exercise.  In other words, you should be able to do the homework without doing this exercise.
  1. Obtain a Filickr API key
  2. Install Flickr library
  3. Create "Ruby on Rails" netBeans project
  4. Add Flickr settings to the project
  5. Add styles to the project
  6. Create a Controller
  7. Modify and create Views
  8. Set URL routing
  9. Run the application
  10. Add spinner to the application

(2.0) Obtain a Flickr API key


1. In your web browser, go to http://www.flickr.com/services/api/misc.api_keys.html.
2. Click Apply for your key online now.


Figure-2.01: Apply for Flickr key

3. Follow the steps for obtaining a Flickr key.
4. Copy the API key that Flickr generates and save it in a text file or other convenient location.


(2.1) Install Flickr library

In this step, you are going to install rflickr library. 

Note:  If you are using NetBeans 6.0 or 6.0.1, you have to use the latest version of Ruby and Rails plug-in. Otherwise, you might experience OutOfMemoryError: Java heap space exception.

0. Reinstall Ruby and Rails plug-in.


Figure-2.02: Uninstall Ruby and Rails plug-in


Figure-2.03: Uninstall


Figure-2.04: Finish the uninstallation.


Figure-2.05: Reinstall the Ruby and Rails plug-in.


1. Install rflickr library.


Figure-2.11: Select Ruby Gems

Figure-2.12: Search for a Gem

Figure-2.13: Install rflickr

Figure-2.14: Gem Installation Settings

Figure-2.15: Installation

Figure-2.16: Close the Ruby Gems dialog box

Trouble-shooting: If you experience "java.lang.OutOfMemoryError: Java heap space " Exception while opening gem window" problem, it is becaue the the Ruby on Rails plug-in that comes with NetBeans 6.0 and 6.0.1 consumes large amount of heap space. Please uninstall and install the new version of the Ruby on Rails plug-in as described above.


Figure-2.17: java.lang.OutOfMemoryError Exception

                                                                                                                                                          return to top of the exercise

(2.2) Create "Ruby on Rails" NetBeans project


1. Create a new NetBeans project.

Figure-2.21: Create a new project

Figure-2.22: Create Ruby on Rails Application

Figure-2.23: Name and Location pane

Figure-2.24: Ruby on Rails directories

                                                                                                                                                          return to top of the exercise


(2.3) Add Flickr settings to the project


1. Add Flickr settings to the environment.rb file.
require 'rubygems'
require 'flickr'
MY_KEY='0c457d8d59ae7a9af78dddd0a298338b'
class Flickr
  alias old_initialize initialize
  def initialize(api_key=MY_KEY, email=nil, password=nil)
    puts "new_initialize " + MY_KEY
    old_initialize(api_key, email, password)
    @host="http://api.flickr.com"
    @activity_file='flickr_activity_cache.xml'
  end
end
Code-2.31: Configure Flickr environment

Figure-2.32: Flickr environment

                                                                                                                                                          return to top of the exercise

(2.4) Add styles to the project


A layout defines the surroundings of an HTML page. It's the place to define common look and feel of your final output. Layout files reside in app/views/layouts.  The process involves defining a layout template and then letting the controller know that it exists and to use it.

1. Create a layout.

Figure-2.41:  Create RHMTL file

Figure-2.42: Name and Location pane

2. Create application-wide layout file.
<Study point: Layout> At rendering time, the layout will yield the results of the template fragment's execution in place.  Note that wherever you put the <%= yield %> keyword is where the contents is placed.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
    <head>
    <title>Flickr</title>
      <%= javascript_include_tag :defaults %>
      <%= stylesheet_link_tag 'flickr' %>
    </head>
<body>
      <%= yield %>
</body>
</html>
Code-2.43: Modified application.rhtml

Figure-2.44: application.rhtml

3. Create a CSS file.

Figure-2.45: Create stylesheet

Figure-2.46: Create Cascading Style Sheet

Figure-2.47: Name ane Location
body {
    background-color: #888;
    font-family: Lucida Grande;
    font-size: 11px;
    margin: 25px;
}

form {
    margin: 0;
    margin-bottom: 10px;
    background-color: rgb(222,231,236);
    border: 5px solid #333;
    padding: 25px;
}


fieldset {
    border: none;
}

#spinner {
    float: right;
    margin: 10px;
}

#photos img {
    border: 1px solid #000;
    width: 75px;
    height: 75px;
    margin: 5px;
}
Code-2.48: flickr.css

Figure-2.49: flickr.css

                                                                                                                                            return to top of the exercise


(2.5) Create a Controller


1. Create a Controller.

Figure-2.51: Generate Controller

Figure-2.52: Create Controller

Figure-2.53: flickr_controller.rb

2. Modify flickr_controller.rb.
<Study point: Partials> Partials are “partial views”—fragments of RHTML that can be included in a view. They allow you to factor and reuse view logic.  You will need to create a partial view called _photo.rhtml in subsequent step.

class FlickrController < ApplicationController
 
  def index
  end
 
  def search
    flickr = Flickr.new

    if params[:tags].empty?
      render :text => '<h2>Please enter a search string</h2>'
    else
      begin
        photos = flickr.photos(:tags => params[:tags], :per_page => '24')
        render :partial => 'photo', :collection => photos
      rescue NoMethodError
        render :text => '<h2>No matching photos found</h2>'
      end
    end
  end
Code-2.54: Modified flickr_controller.rb
Figure-2.55: Modified flickr_controller.rb
                                                                                                                                             return to top of the exercise


(2.6) Modify and create Views


1. Modify index.rhtml.
<% form_remote_tag :url => {:action => 'search'}, :update => 'photos' do %>
    <fieldset>
        <label for="tags">Tags:</label>

        <%= text_field_tag 'tags' %>
        <%= submit_tag 'Find' %>
    </fieldset>

    <div id="photos"></div>
<% end %>
Code-2.61: Modified index.rhtml

Figure-2.62: Modified index.rhtml

2.  Create a new Partial View.

Figure-2.63: Create new RHTML file

Figure-2.64: Name and Location
<%#
# To change this template, choose Tools | Templates
# and open the template in the editor.
%>

<img class='photo' src="<%= photo.sizes[0]['source'] %>">

Figure-2.65: _photo.rhtml

                                                                                                                                                 return to top of the exercise

(2.7) Set URL routing


1. Set URL routing
map.connect "", :controller => 'flickr'

Figure-2,72: Modified routes.rb

2. Delete default index.html.

Figure-2.73: Delete index.html

Figure-2.74: Confirmation

                                                                                                                                             return to top of the exercise

   

(2.8) Run the application


1. Run the application

Figure-2.81: Run Main Project

Figure-2.82: Perform the Find operation

Figure-2.83: Result of the Find operation

                                                                                                                                          return to top of the exercise


(2.9) Add spinner to the application


1. Copy spinner.gif to the project.

Figure-2.91: Add spinner.gif file

2. Modify index.rhtml.
<% form_remote_tag :url => {:action => 'search'}, :update => 'photos',
    :complete => visual_effect(:blind_down, 'photos'),
    :before   => %(Element.show('spinner')),
    :success  => %(Element.hide('spinner')) do %>

    <%= image_tag 'spinner.gif', :id => 'spinner', :style => 'display: none' %>
    <fieldset>
        <label for="tags">Tags:</label>
        <%= text_field_tag 'tags' %>

        <%= submit_tag 'Find' %>
    </fieldset>

    <div id="photos" style="display: none"></div>

<% end %>
Code-2.92: Modified index.rhtml

Figure-2.93: Modified index.rhtml

3. Run the application.

Figure-2.94: Spinner is being displayed

                                                                                                                    return to top of the exercise

Solution


The solution of this exercise is provided as a ready-to-build NetBeans project -  <LAB_UNZIP_DIR>/jrubyrailsbasics/samples/Flickr.  You should be able to build and run the project.

Summary

In this exercise,  you have built and run a "flickr" sample application. 

                                                                                                                    return to the top



Homework Exercise (for people who are taking Sang Shin's "Java EE Programming online course")


1. The homework is to modify RubyWebLog project as following. (You might want to create a new project by copying the RubyWebLog project.  You can name the homework project in any way you want but here I am going to call it MyRubyWebLog.)

                                                                                                                    return to the top