Ruby on Rails

Rapid and Sustainable Web Development

Frank S. Kim

betweenGo

Ruby on Rails

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


  def set_user_city_state(zipcode)
    zipcode_info = Zipcode.find_by_zipcode zipcode
    ...
  end
  

Instant Feedback

Goodies

Testing Framework

Tournament Application - Create

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


[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


[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 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


[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


[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

  • 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

Credits