Ruby on Rails
Rapid and Sustainable Web Development
Frank S. Kim
betweenGo
Ruby on Rails
- Ruby
- MVC framework
- DRY (Don't Repeat Yourself)
- instant feedback
- code generators, AJAX support, integrated web services
support, etc.
- built-in testing framework
- tournament sign-up application
Ruby
- interpreted scripting language
- portable, available on most operating systems
- free, which means not only free of charge, but also freedom to
use, copy, modify, and distribute it
- pure object oriented language, all data is an object
- very lax rules when it comes to syntax
- for more info: What's Ruby
Ruby
class Project < ActiveRecord::Base
belongs_to :portfolio
has_one :project_manager
has_many :milestones
has_and_belongs_to_many :categories
validates_presence_of :name, :description
vaidates_acceptance_of :non_disclosure_ageement
valdates_uniqueness_of :key
attr_accessor :password
end
Model-View-Controller Architecture
|
- model, state of the application
- view, how the user interacts with the application
- controller, receives input from user, interacts with model, and
displays appropriate view
- Rails enforces MVC structure
|
Don't Repeat Yourself
- single language from top to bottom
- convention over configuration
- Rails shuns configuration files and annotations in favor of
reflection and run-time extensions
- no XML
def set_user_city_state(zipcode)
zipcode_info = Zipcode.find_by_zipcode zipcode
...
end
Instant Feedback
- code changes are immediately available
- no compilation phase
- deployment is trivial
Goodies
- code generators
- AJAX support (e.g. GMail)
- integrated web services support
- reception of incoming e-mails
Testing Framework
- integrated
- isolated environments for development, testing, production
- unit tests (like JUnit)
- functional tests (like Cactus)
- mock objects (e.g. simulate backend system)
Tournament Application - Create
- simple web application for signing up for a basketball tournament
- issue rails command to create application
- start WEBrick server to see application
C:\cygwin\home\Fkim>rails nktournament
create
create app/controllers
create app/helpers
create app/models
create app/views/layouts
create config/environments
create components
create db
create doc
create lib
create lib/tasks
create log
create public/images
create public/javascripts
create public/stylesheets
create script/performance
create script/process
create test/fixtures
create test/functional
create test/mocks/development
create test/mocks/test
create test/unit
create vendor
create vendor/plugins
create Rakefile
create README
create app/controllers/application.rb
create app/helpers/application_helper.rb
create test/test_helper.rb
create config/database.yml
create config/routes.rb
create public/.htaccess
create config/boot.rb
create config/environment.rb
create config/environments/production.rb
create config/environments/development.rb
create config/environments/test.rb
create script/about
create script/breakpointer
create script/console
create script/destroy
create script/generate
create script/performance/benchmarker
create script/performance/profiler
create script/process/reaper
create script/process/spawner
create script/process/spinner
create script/runner
create script/server
create script/plugin
create public/dispatch.rb
create public/dispatch.cgi
create public/dispatch.fcgi
create public/404.html
create public/500.html
create public/index.html
create public/favicon.ico
create public/robots.txt
create public/javascripts/prototype.js
create public/javascripts/effects.js
create public/javascripts/dragdrop.js
create public/javascripts/controls.js
create doc/README_FOR_APP
create log/server.log
create log/production.log
create log/development.log
create log/test.log
C:\cygwin\home\Fkim>cd nktournament
Tournament Application - Database
- create database for tournament
- create SQL script in db directory for teams table and execute it
CREATE TABLE teams (
id int unsigned NOT NULL AUTO_INCREMENT,
name varchar(64) NOT NULL,
organization varchar(64) NOT NULL,
captain_first_name varchar(64) NOT NULL,
captain_last_name varchar(64) NOT NULL,
email varchar(64) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY name (name)
) TYPE=InnoDB;
C:\cygwin\home\Fkim\nktournament>mysql < db\teams.sql
Tournament Application - Teams
- configure application about which database to use and then
restart application
- run code generator to create pages for listing, viewing,
creating, and deleting teams
[config/database.yml]
development:
adapter: mysql
database: kimplicity
username: shawn
password: becker
socket: /path/to/your/mysql.sock
C:\cygwin\home\Fkim\nktournament>ruby script\generate scaffold Team Team
exists app/controllers/
exists app/helpers/
create app/views/team
exists test/functional/
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/team.rb
create test/unit/team_test.rb
create test/fixtures/teams.yml
create app/views/team/_form.rhtml
create app/views/team/list.rhtml
create app/views/team/show.rhtml
create app/views/team/new.rhtml
create app/views/team/edit.rhtml
create app/controllers/team_controller.rb
create test/functional/team_controller_test.rb
create app/helpers/team_helper.rb
create app/views/layouts/team.rhtml
create public/stylesheets/scaffold.css
C:\cygwin\home\Fkim\nktournament>ruby script\server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2005-11-13 13:20:13] INFO WEBrick 1.3.1
[2005-11-13 13:20:13] INFO ruby 1.8.2 (2004-12-25) [i386-mswin32]
[2005-11-13 13:20:13] INFO WEBrick::HTTPServer#start: pid=5688 port=3000
Tournament Application - Validation
- validate that all fields are entered
- validate that email address is the correct format
[app/model/team.rb]
class Team < ActiveRecord::Base
validates_presence_of :name, :organization,
:captain_first_name, :captain_last_name, :email
validates_format_of :email,
:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/
end
Tournament Application - Players
- create SQL script in db directory for players table and execute it
- run code generator to create pages for listing, viewing,
creating, and deleting players
CREATE TABLE players (
id int unsigned NOT NULL AUTO_INCREMENT,
team_id int unsigned NOT NULL,
first_name varchar(64) NOT NULL,
last_name varchar(64) NOT NULL,
PRIMARY KEY (id)
) TYPE=InnoDB;
C:\cygwin\home\Fkim\nktournament>mysql < db\players.sql
C:\devel\web\nktournament>ruby script\generate model player
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/player.rb
create test/unit/player_test.rb
create test/fixtures/players.yml
Tournament Application - Association
- each team has many players and each player belongs to one team
[app/model/team.rb]
class Team < ActiveRecord::Base
has_many :players
...
end
[app/model/player.rb]
class Player < ActiveRecord::Base
belongs_to :teams
validates_presence_of :first_name, :last_name
end
Tournament Application - Team Players
- list players on team page
[app/views/team/show.rhtml]
<b>Players</b>
<table>
<% for player in @team.players %>
<tr>
<td>
<%=h player.first_name %> <%=h player.last_name %>
</td>
</tr>
<% end %>
</table>
Tournament Application - Add Player I
[app/views/team/show.rhtml]
<%= link_to 'Add Player', :action => 'add_player', :id => @team %> |
[app/controllers/team_controller.rb]
def add_player
@player = Player.new
end
Tournament Application - Add Player II
[app/views/team/add_player.rhtml]
<h1>Add Player</h1>
<%= start_form_tag :action => 'add_player' %>
<%= error_messages_for 'player' %>
<p><label for="player_first_name">First Name</label><br/>
<%= text_field 'player', 'first_name' %></p>
<p><label for="player_last_name">Last Name</label><br/>
<%= text_field 'player', 'last_name' %></p>
<input type="hidden" name="id" value="#{@team}"/>
<%= submit_tag 'Add Player' %>
<%= end_form_tag %>
<%= link_to 'Back', :action => 'show', :id => @team %>
Tournament Application - Add Player III
[app/controllers/team_controller.rb]
def add_player
case @request.method; when :get
@team = Team.find(params[:id])
@player = Player.new
when :post
@team = Team.find(params[:id])
@player = Player.new(params[:player])
@team.players << @player
if @team.save
flash[:notice] = 'Player was successfully added.'
redirect_to :action => 'show', :id => params[:id]
else
render :action => 'add_player'
end
end
end
Problems
- Rails is still in development and has not reached version 1.0.
Bugs and upgrade issues still exist.
- online documentation is good but incomplete and sometimes
contradicting, get Agile
Web Development with Rails
- personalization and commerce frameworks are not part of Rails
- code generators do not have a merge function
- Bugs still exist but are decreasing. Rails upgrades have
been known to break existing applications but this situation is
improving.
- Agile
Web Development with Rails is a must have because it is the
only source of documentation which is well-thought out,
consistent, and organized
- login, authentication, authorization, user roles is not part
of Rails. The current state of Ruby gems, generators, plugins,
and modules is patchy and sometimes buggy.
- Ruby gems, generators, plugins and modules exist for
different aspects of personalization and commerce exist but
again it is patchy and sometimes buggy
- when a code generator is updated you must run the code
generator in a separate area and then merge in the changes