SlideShare ist ein Scribd-Unternehmen logo
1 von 60
Downloaden Sie, um offline zu lesen
Cheap, Fast, and Good
You can have it all with Ruby on Rails
              Brian McCallister
          brianm@chariotsolutions.com
         http://www.chariotsolutions.com/




                 (c) 2005, Brian McCallister
What is Ruby?
• Dynamic and Interpreted
• Strong support for OO programming
 • Everything is an object ( 2.next == 3 )
• Strong support for functional-style
  programming
 • Blocks, closures, first-class functions
• Child of Perl and Smalltalk

                (c) 2005, Brian McCallister
What is Rails?
• Model-2 Web Framework
• Object/Relational Mapping Library
• SOAP Producer/Consumer Framework
• Email Templating/Mailing Library
• Code Generator
• Very Rapidly Evolving!
               (c) 2005, Brian McCallister
Principles Involved
• Less Code
• Convention over Configuration
• Proximity
• Least Surprise
• Make components play nicely together!

              (c) 2005, Brian McCallister
Action Pack
  That Web Stuff




  (c) 2005, Brian McCallister
Request Cycle




   (c) 2005, Brian McCallister
Some Code
require 'date'

class AggregateController < ApplicationController

 model :entry

 def for_date
   date = DateTime.parse @params[:date]
   logger.debug quot;for_date: #{date}quot;
   @entries = Entry.on_date date
 end

 # Additional actions removed for slide’s benefit`

end




                   (c) 2005, Brian McCallister
Action
require 'date'

class AggregateController < ApplicationController

 model :entry
                                                 Action
 def for_date
   date = DateTime.parse @params[:date]
   logger.debug quot;for_date: #{date}quot;
   @entries = Entry.on_date date
 end

 # Additional actions removed for slide’s benefit`

end




                   (c) 2005, Brian McCallister
Controller
                                                 Controller
require 'date'

class AggregateController < ApplicationController

 model :entry
                                                  Action
 def for_date
   date = DateTime.parse @params[:date]
   logger.debug quot;for_date: #{date}quot;
   @entries = Entry.on_date date
 end
                                                  Action
 def list_entries
   @entries = Entry.find_all
 end

 # Additional actions removed for slide’s benefit`

end

                   (c) 2005, Brian McCallister
How We Got Here
ActionController::Routing::Routes.draw do |map|

  # map.connect ':controller/service.wsdl',
  #             :action => 'wsdl'

  map.connect 'wombat/is/friendly',

             :controller => :feeds,
              :action => :list

  map.connect '',
              :controller => :feeds,
              :action => :list

  # Default Route
  map.connect ':controller/:action/:id'
end




                   (c) 2005, Brian McCallister
routes.rb
ActionController::Routing::Routes.draw do |map|
                     http://localhost/wombat/is/friendly
  # map.connect ':controller/service.wsdl',
  #             :action => 'wsdl'

  map.connect 'wombat/is/friendly',

             :controller => :feeds,
              :action => :list

  map.connect '',
              :controller => :feeds,
              :action => :list

  # Default Route
  map.connect ':controller/:action/:id'
end




                   (c) 2005, Brian McCallister
routes.rb
ActionController::Routing::Routes.draw do |map|

  # map.connect ':controller/service.wsdl',
  #             :action => 'wsdl'

  map.connect 'wombat/is/friendly',
                                                 http://localhost/

             :controller => :feeds,
              :action => :list

  map.connect '',
              :controller => :feeds,
              :action => :list

  # Default Route
  map.connect ':controller/:action/:id'
end




                   (c) 2005, Brian McCallister
routes.rb
ActionController::Routing::Routes.draw do |map|

  # map.connect ':controller/service.wsdl',
  #             :action => 'wsdl'

  map.connect 'wombat/is/friendly',

             :controller => :feeds,
              :action => :list

  map.connect '',
              :controller => :feeds,
                           http://localhost/feeds/list
              :action => :list

  # Default Route
  map.connect ':controller/:action/:id'
end




                    (c) 2005, Brian McCallister
Show Us Something!
<h1>Recent Stories...</h1>
<table class=quot;entryTablequot; >
<% for entry in @entries %>
  <tr>
    <td class=quot;entryTitlequot;>
      <%= entry.feed.title + quot;: quot; + entry.title %>
    </td>
  </tr>
  <tr>
    <td class=quot;entryBodyquot;>
      <%= entry.body %>
    </td>
  </tr>
<% end %>
</table>




                   (c) 2005, Brian McCallister
Directives
<h1>Recent Stories...</h1>
<table class=quot;entryTablequot; >
<% for entry in @entries %>
  <tr>
    <td class=quot;entryTitlequot;>
      <%= entry.feed.title + quot;: quot; + entry.title %>
    </td>
  </tr>
  <tr>
    <td class=quot;entryBodyquot;>
      <%= entry.body %>
    </td>
  </tr>
<% end %>
</table>




                   (c) 2005, Brian McCallister
Expressions
<h1>Recent Stories...</h1>
<table class=quot;entryTablequot; >
<% for entry in @entries %>
  <tr>
    <td class=quot;entryTitlequot;>
      <%= entry.feed.title + quot;: quot; + entry.title %>
    </td>
  </tr>
  <tr>
    <td class=quot;entryBodyquot;>
      <%= entry.body %>
    </td>
  </tr>
<% end %>
</table>




                   (c) 2005, Brian McCallister
Helpers & Partials
<h1>Recent Stories...</h1>
                                      my_view.rhtml
<%=

   render_partial quot;entry_listquot;,






             :stories => @entries
 %>

<table class=quot;entryTablequot; >
                                     _entry_list.rhtml
<% for entry in stories %>
  <tr>
    <td class=quot;entryTitlequot;>
      <%= entry.feed.title + quot;: quot; + entry.title %>
    </td>
  </tr>
  <tr>
    <td class=quot;entryBodyquot;>
      <%= entry.body %>
    </td>
  </tr>
<% end %>
</table>
                   (c) 2005, Brian McCallister
Helpers
<h1>Recent Stories...</h1>
                                      my_view.rhtml
<%=

   render_partial quot;entry_listquot;,






             :stories => @entries
 %>

<table class=quot;entryTablequot; >
                                     _entry_list.rhtml
<% for entry in stories %>
  <tr>
    <td class=quot;entryTitlequot;>
      <%= entry.feed.title + quot;: quot; + entry.title %>
    </td>
  </tr>
  <tr>
    <td class=quot;entryBodyquot;>
      <%= entry.body %>
    </td>
  </tr>
<% end %>
</table>
                   (c) 2005, Brian McCallister
Parameterized Partials
<h1>Recent Stories...</h1>
                                      my_view.rhtml
<%=

   render_partial quot;entry_listquot;,






             :stories => @entries
 %>

<table class=quot;entryTablequot; >
                                     _entry_list.rhtml
<% for entry in stories %>
  <tr>
    <td class=quot;entryTitlequot;>
      <%= entry.feed.title + quot;: quot; + entry.title %>
    </td>
  </tr>
  <tr>
    <td class=quot;entryBodyquot;>
      <%= entry.body %>
    </td>
  </tr>
<% end %>
</table>
                   (c) 2005, Brian McCallister
Picking Views
• Default Views
• The View for that one over there...
• Named Views
• Something completely different?



               (c) 2005, Brian McCallister
Default Views
require 'date'

class AggregateController < ApplicationController

 model :entry
                         aggregate/for_date.rhtml
 def for_date
   date = DateTime.parse @params[:date]
   logger.debug quot;for_date: #{date}quot;
   @entries = Entry.on_date date
 end

 # Additional actions removed for slide’s benefit`

end




                   (c) 2005, Brian McCallister
render_*
require 'date'

class AggregateController < ApplicationController

 model :entry

 def today
   @entries = Entry.on_date Date.today
   render_action :list_entries
 end
                            aggregate/list_entries.rhtml
 def list_entries
   @entries = Entry.find_all
 end

 # Additional actions removed for slide’s benefit`

end


                   (c) 2005, Brian McCallister
Named Views
require 'date'

class AggregateController < ApplicationController

 model :entry

 def another_one
   @entries = Entry.find_all
   render :a_template
                                         a_template.rhtml
 end

 # Additional actions removed for slide’s benefit`

end




                   (c) 2005, Brian McCallister
Raw Rendering
require 'date'

class AggregateController < ApplicationController

 model :entry

 def direct_write
   render_text quot;Hello World!quot;
 end
                                                 No template!
 # Additional actions removed for slide’s benefit`

end




                   (c) 2005, Brian McCallister
Additional Options
• send_data
• send_file
• render_to_string
• render_nothing
• render_text with a block
• redirect_to
• redirect_to_url
• redirect_to_path
• builders
• and more!
               (c) 2005, Brian McCallister
Helpers
• Programmatic output generation
• Global, Controller Specific, Importable
• Like tag libraries
 • kind of
• Lots of built-ins


               (c) 2005, Brian McCallister
#{Controller}Helper
module AggregateHelper

 def say_hello(name)
                                                 Helper
   quot;<h1>Hello, #{name}quot;
 end

end




<h1>Recent Stories...</h1>
                                                 Usage
<%= say_hello quot;Brianquot; %>
<table>
<% for entry in @entries %>
...




                   (c) 2005, Brian McCallister
Rules, well Suggestions
• #{Controller}Helper applied from
  matching Controller
• ApplicationHelper available everywhere
• Declare reliance on a specific Helper
  from any Controller
 • Rarely need to do this, though


               (c) 2005, Brian McCallister
Action Pack Magic 3
• Controllers
• Helpers
• Views
• Things not discussed:
 • Components
 • Caching
 • Filters
                (c) 2005, Brian McCallister
Active Record
You get the data from the database
      and shake it all about...




          (c) 2005, Brian McCallister
Active Record Basics
• Not Required!
• One Row == One Instance
• Dynamic Properties by Default
• Query by SQL or Criteria
 • Including joins
• PostgreSQL, MySQL, Oracle, DB2 ... more

              (c) 2005, Brian McCallister
The Schema




  (c) 2005, Brian McCallister
The Classes
class Feed < ActiveRecord::Base
  has_many :entries

 validates_presence_of :title, :url

end


...


class Entry < ActiveRecord::Base
  belongs_to :feed

 validates_presence_of :title, :body, :entry_uid
 validates_uniqueness_of :entry_uid

end


                   (c) 2005, Brian McCallister
Relations
class Feed < ActiveRecord::Base
  has_many :entries

 validates_presence_of :title, :url

end


...


class Entry < ActiveRecord::Base
  belongs_to :feed

 validates_presence_of :title, :body, :entry_uid
 validates_uniqueness_of :entry_uid

end


                   (c) 2005, Brian McCallister
Queries
def Entry.recent(count)
  Entry.find :all,
             :order =>'created_on DESC',
             :limit => count,
             :include => [:feed]
end

def Entry.after(date)
  Entry.find :all,



          :conditions => ['created_on >= ?', date],
             :order => 'created_on DESC',
             :include => [:feed]
end

def Entry.before(date)
  Entry.find_by_sql [quot;select e.* from entries e where
                      created_on < ?quot;, date]
end


                    (c) 2005, Brian McCallister
Criteria
def Entry.recent(count)
  Entry.find :all,
             :order =>'created_on DESC',
             :limit => count,
             :include => [:feed]
end

def Entry.after(date)
  Entry.find :all,



          :conditions => ['created_on >= ?', date],
             :order => 'created_on DESC',
             :include => [:feed]
end

def Entry.before(date)
  Entry.find_by_sql [quot;select e.* from entries e where
                      created_on < ?quot;, date]
end


                    (c) 2005, Brian McCallister
SQL
def Entry.recent(count)
  Entry.find :all,
             :order =>'created_on DESC',
             :limit => count,
             :include => [:feed]
end

def Entry.after(date)
  Entry.find :all,



          :conditions => ['created_on >= ?', date],
             :order => 'created_on DESC',
             :include => [:feed]
end

def Entry.before(date)
  Entry.find_by_sql [quot;select e.* from entries e where
                      created_on < ?quot;, date]
end


                    (c) 2005, Brian McCallister
Code Generator
    This stuff rocks!




     (c) 2005, Brian McCallister
Creating Rails Project
brianm@kite:~/Sites$ rails apachecon
      create app
      create app/apis
      create app/controllers
      create app/helpers
      create app/models

 
 ...
      create log/test.log

brianm@kite:~/Sites$ ls -F apachecon/

CHANGELOG   Rakefile        components/ db/          lib/
public/     test/           README      app/         config/
doc/        log/            script/     vendor/

brianm@kite:~/Sites$



                       (c) 2005, Brian McCallister
This Created...
• Project Hierarchy
• Config file (for database connection)
• Rakefile (Makefile)
• System Test Harness
• Unit Test Harness
• Apache HTTPD Configs (.htaccess)
• Additional Code Generation Scripts...
               (c) 2005, Brian McCallister
Configure Database
brianm@kite:~/Sites/apachecon$ cat config/
database.yml
development:
  adapter: postgresql
  database: ruby_blogs_dev
  host: localhost
  username: blogs
  password: **********

...

production:
  adapter: postgresql
  database: ruby_blogs
  host: localhost
  username: blogs
  password: **********
brianm@kite:~/Sites/apachecon$


                    (c) 2005, Brian McCallister
Some CRUD
brianm@kite:~/Sites/apachecon$ ./script/generate scaffold Talk
  dependency model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
      create    app/models/talk.rb
      create    test/unit/talk_test.rb
      create    test/fixtures/talks.yml
      exists app/controllers/
      exists app/helpers/
      create app/views/talks
      exists test/functional/
      create app/controllers/talks_controller.rb
      create test/functional/talks_controller_test.rb
      create app/helpers/talks_helper.rb
      create app/views/layouts/talks.rhtml
      create public/stylesheets/scaffold.css
      create app/views/talks/list.rhtml
      create app/views/talks/show.rhtml
      create app/views/talks/new.rhtml
      create app/views/talks/edit.rhtml
      create app/views/talks/_form.rhtml
brianm@kite:~/Sites/apachecon$


                        (c) 2005, Brian McCallister
A Table
apachecon=> create table talks (

 id serial primary key,

 name varchar(255) not null,

 presenter varchar(255) not null,
   description text not null);

NOTICE: CREATE TABLE will create implicit sequence

 
 
 
 quot;sessions_id_seqquot; for serial column quot;sessions.idquot;
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index

 
 
 
 quot;sessions_pkeyquot; for table quot;sessionsquot;
CREATE TABLE
apachecon=>




                        (c) 2005, Brian McCallister
Start the Server...
brianm@kite:~/Sites/apachecon$ ./script/server
=> Rails application started on http://0.0.0.0:3000
[2005-05-25 18:00:12] INFO WEBrick 1.3.1
[2005-05-25 18:00:12] INFO ruby 1.8.2 (2004-12-25)
[2005-05-25 18:00:12] INFO WEBrick::HTTPServer#start:
pid=26996 port=3000




                     (c) 2005, Brian McCallister
List




(c) 2005, Brian McCallister
TalksController
class TalksController < ApplicationController
  def index
    list
    render_action 'list'
  end

 def list
   @talk_pages, @talks = paginate :talk, :per_page => 10
 end

 def show
   @talk = Talk.find(@params[:id])
 end

 ...

end



                      (c) 2005, Brian McCallister
Create




(c) 2005, Brian McCallister
The Edit View
<h1>Editing talk</h1>
<%= start_form_tag :action => 'update', :id => @talk %>
  <%= render_partial quot;formquot; %>
  <%= submit_tag quot;Editquot; %>
                                                        talks/edit.rhtml
<%= end_form_tag %>

<%= link_to 'Show', :action => 'show', :id => @talk %> |
<%= link_to 'Back', :action => 'list' %>


<%= error_messages_for 'talk' %>

<!--[form:talk]-->
<p><label for=quot;talk_descriptionquot;>Description</label><br/>
<%= text_area 'talk', 'description' %></p>

<p><label for=quot;talk_presenterquot;>Presenter</label><br/>
<%= text_field 'talk', 'presenter' %></p>

                                                       talks/_form.rhtml
<p><label for=quot;talk_namequot;>Name</label><br/>
<%= text_field 'talk', 'name' %></p>
<!--[eoform:talk]-->
                         (c) 2005, Brian McCallister
List Again




 (c) 2005, Brian McCallister
Unit and System Tests
brianm@kite:~/Sites/apachecon$ rake
(in /Users/brianm/Sites/apachecon)
ruby -Ilib:test quot;/usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/
rake/rake_test_loader.rbquot; quot;test/unit/talk_test.rbquot;
Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/
rake_test_loader
Started
.
Finished in 0.11654 seconds.

1 tests, 1 assertions, 0 failures, 0 errors
ruby -Ilib:test quot;/usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/
rake/rake_test_loader.rbquot; quot;test/functional/
talks_controller_test.rbquot;
Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/
rake_test_loader
Started
........
Finished in 0.456943 seconds.

8 tests, 26 assertions, 0 failures, 0 errors
brianm@kite:~/Sites/apachecon$
                          (c) 2005, Brian McCallister
.htaccess
# General Apache options
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI
# If you don't want Rails to look in certain directories,
# use the following rewrite rules so that Apache won't ... <snip />
#
# Example:
#   RewriteCond %{REQUEST_URI} ^/notrails.*
#   RewriteRule .* - [L]
# Redirect all requests not available on the filesystem to Rails
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
#   RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteEngine On
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
...

                           (c) 2005, Brian McCallister
Extensible Generator
• Some 3rd Party Generators:
 • Login Generator
 • Salted Hash Login Generator
 • Tabbed Navbar Generator
 • Search Generator
 • Configuration Generator
 • Postback Generator
              (c) 2005, Brian McCallister
Deployment Time
   Stuff to be aware of...




       (c) 2005, Brian McCallister
Environment
• Development
• Test
• Production




            (c) 2005, Brian McCallister
Web Servers
• Webrick
• Apache Web Server
 • CGI
 • mod_ruby
 • fastcgi
• lighttpd
 • fastcgi
             (c) 2005, Brian McCallister
Session Storage
• Serialize to /tmp
• DRb Server
• Database
• memcached
• Custom
• No Sessions

                (c) 2005, Brian McCallister
Scaling Up
• Multi-processing model (like prefork)
• DB Connection per FCGI Process
• Remote FCGI instances
• Static and Dynamic Caching
• Easy to interface with C
 •   (Almost as easy to interface with OCaml)




                  (c) 2005, Brian McCallister
The Diagram




   (c) 2005, Brian McCallister
Web Resources
• Ruby
 • http://www.ruby-lang.org/
• Why’s Poignant Guide to Ruby
 • http://poignantguide.net/
• Ruby on Rails
 • http://www.rubyonrails.com/
• Ruby Documentation
 • http://www.ruby-doc.org/
              (c) 2005, Brian McCallister
That’s all folks!
      Brian McCallister
  brianm@chariotsolutions.com
 http://www.chariotsolutions.com/

Weitere ähnliche Inhalte

Was ist angesagt?

AtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and ServerAtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and ServerAtlassian
 
Redux training
Redux trainingRedux training
Redux trainingdasersoft
 
Implement react pagination with react hooks and react paginate
Implement react pagination with react hooks and react paginateImplement react pagination with react hooks and react paginate
Implement react pagination with react hooks and react paginateKaty Slemon
 
SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!Sébastien Levert
 
RubyOnRails-Cheatsheet-BlaineKendall
RubyOnRails-Cheatsheet-BlaineKendallRubyOnRails-Cheatsheet-BlaineKendall
RubyOnRails-Cheatsheet-BlaineKendalltutorialsruby
 
OSCON 2005: Build Your Own Chandler Parcel
OSCON 2005: Build Your Own Chandler ParcelOSCON 2005: Build Your Own Chandler Parcel
OSCON 2005: Build Your Own Chandler ParcelTed Leung
 
AtlasCamp 2015: Using add-ons to build add-ons
AtlasCamp 2015: Using add-ons to build add-onsAtlasCamp 2015: Using add-ons to build add-ons
AtlasCamp 2015: Using add-ons to build add-onsAtlassian
 
React state managmenet with Redux
React state managmenet with ReduxReact state managmenet with Redux
React state managmenet with ReduxVedran Blaženka
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 DreamLab
 
첫 리액트 경험기
첫 리액트 경험기첫 리액트 경험기
첫 리액트 경험기석진 고
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionVisual Engineering
 
Better web apps with React and Redux
Better web apps with React and ReduxBetter web apps with React and Redux
Better web apps with React and ReduxAli Sa'o
 
Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2DreamLab
 

Was ist angesagt? (20)

Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
AtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and ServerAtlasCamp 2015: Connect everywhere - Cloud and Server
AtlasCamp 2015: Connect everywhere - Cloud and Server
 
Redux vs Alt
Redux vs AltRedux vs Alt
Redux vs Alt
 
Redux training
Redux trainingRedux training
Redux training
 
Implement react pagination with react hooks and react paginate
Implement react pagination with react hooks and react paginateImplement react pagination with react hooks and react paginate
Implement react pagination with react hooks and react paginate
 
SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!
 
RubyOnRails-Cheatsheet-BlaineKendall
RubyOnRails-Cheatsheet-BlaineKendallRubyOnRails-Cheatsheet-BlaineKendall
RubyOnRails-Cheatsheet-BlaineKendall
 
OSCON 2005: Build Your Own Chandler Parcel
OSCON 2005: Build Your Own Chandler ParcelOSCON 2005: Build Your Own Chandler Parcel
OSCON 2005: Build Your Own Chandler Parcel
 
React и redux
React и reduxReact и redux
React и redux
 
React lecture
React lectureReact lecture
React lecture
 
Grails Advanced
Grails Advanced Grails Advanced
Grails Advanced
 
AtlasCamp 2015: Using add-ons to build add-ons
AtlasCamp 2015: Using add-ons to build add-onsAtlasCamp 2015: Using add-ons to build add-ons
AtlasCamp 2015: Using add-ons to build add-ons
 
React & redux
React & reduxReact & redux
React & redux
 
React state managmenet with Redux
React state managmenet with ReduxReact state managmenet with Redux
React state managmenet with Redux
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3
 
첫 리액트 경험기
첫 리액트 경험기첫 리액트 경험기
첫 리액트 경험기
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
Workshop 17: EmberJS parte II
Workshop 17: EmberJS parte IIWorkshop 17: EmberJS parte II
Workshop 17: EmberJS parte II
 
Better web apps with React and Redux
Better web apps with React and ReduxBetter web apps with React and Redux
Better web apps with React and Redux
 
Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2Quick start with React | DreamLab Academy #2
Quick start with React | DreamLab Academy #2
 

Andere mochten auch

Driving In Bolivia (1)
Driving In Bolivia (1)Driving In Bolivia (1)
Driving In Bolivia (1)mrpagane
 
Surrogacy: The taboo form of conception
Surrogacy: The taboo form of conceptionSurrogacy: The taboo form of conception
Surrogacy: The taboo form of conceptionkelseyraewilliams
 
1st Chinaonrails Open Course
1st Chinaonrails Open Course1st Chinaonrails Open Course
1st Chinaonrails Open CourseJesse Cai
 
Rails training presentation routing
Rails training presentation   routingRails training presentation   routing
Rails training presentation routingtheacadian
 
Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012
Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012
Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012Andy Maleh
 

Andere mochten auch (6)

Index
IndexIndex
Index
 
Driving In Bolivia (1)
Driving In Bolivia (1)Driving In Bolivia (1)
Driving In Bolivia (1)
 
Surrogacy: The taboo form of conception
Surrogacy: The taboo form of conceptionSurrogacy: The taboo form of conception
Surrogacy: The taboo form of conception
 
1st Chinaonrails Open Course
1st Chinaonrails Open Course1st Chinaonrails Open Course
1st Chinaonrails Open Course
 
Rails training presentation routing
Rails training presentation   routingRails training presentation   routing
Rails training presentation routing
 
Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012
Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012
Revised Rails Engine Patterns for Montreal.rb meetup Oct 16, 2012
 

Ähnlich wie Apachecon Rails

Rails 2.3 and Rack - NHRuby Feb 2009
Rails 2.3 and Rack - NHRuby Feb 2009Rails 2.3 and Rack - NHRuby Feb 2009
Rails 2.3 and Rack - NHRuby Feb 2009bturnbull
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsViget Labs
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsBen Scofield
 
Java Web Programming [5/9] : EL, JSTL and Custom Tags
Java Web Programming [5/9] : EL, JSTL and Custom TagsJava Web Programming [5/9] : EL, JSTL and Custom Tags
Java Web Programming [5/9] : EL, JSTL and Custom TagsIMC Institute
 
Rails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity PresentationRails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity Presentationrailsconf
 
ASP.Net 3.5 SP1 Dynamic Data
ASP.Net 3.5 SP1 Dynamic DataASP.Net 3.5 SP1 Dynamic Data
ASP.Net 3.5 SP1 Dynamic Datamicham
 
DOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A RideDOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A RideMatthew McCullough
 
Simplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a VengeanceSimplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a Vengeancebrianauton
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsMark
 
So you want to build a facebook App ?
So you want to build a facebook App ?So you want to build a facebook App ?
So you want to build a facebook App ?Nguyễn Duy Nhân
 
Implementation of GUI Framework part3
Implementation of GUI Framework part3Implementation of GUI Framework part3
Implementation of GUI Framework part3masahiroookubo
 
Taking Apache Camel For A Ride
Taking Apache Camel For A RideTaking Apache Camel For A Ride
Taking Apache Camel For A RideBruce Snyder
 
Web applications with Catalyst
Web applications with CatalystWeb applications with Catalyst
Web applications with Catalystsvilen.ivanov
 
Spring-training-in-bangalore
Spring-training-in-bangaloreSpring-training-in-bangalore
Spring-training-in-bangaloreTIB Academy
 
Drupalcon 2023 - How Drupal builds your pages.pdf
Drupalcon 2023 - How Drupal builds your pages.pdfDrupalcon 2023 - How Drupal builds your pages.pdf
Drupalcon 2023 - How Drupal builds your pages.pdfLuca Lusso
 
2023 - Drupalcon - How Drupal builds your pages
2023 - Drupalcon - How Drupal builds your pages2023 - Drupalcon - How Drupal builds your pages
2023 - Drupalcon - How Drupal builds your pagessparkfabrik
 
GHC Participant Training
GHC Participant TrainingGHC Participant Training
GHC Participant TrainingAidIQ
 
Acceptance Testing with Webrat
Acceptance Testing with WebratAcceptance Testing with Webrat
Acceptance Testing with WebratLuismi Cavallé
 
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember DataIn The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember DataColdFusionConference
 

Ähnlich wie Apachecon Rails (20)

Rails 2.3 and Rack - NHRuby Feb 2009
Rails 2.3 and Rack - NHRuby Feb 2009Rails 2.3 and Rack - NHRuby Feb 2009
Rails 2.3 and Rack - NHRuby Feb 2009
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Java Web Programming [5/9] : EL, JSTL and Custom Tags
Java Web Programming [5/9] : EL, JSTL and Custom TagsJava Web Programming [5/9] : EL, JSTL and Custom Tags
Java Web Programming [5/9] : EL, JSTL and Custom Tags
 
Rails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity PresentationRails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity Presentation
 
ASP.Net 3.5 SP1 Dynamic Data
ASP.Net 3.5 SP1 Dynamic DataASP.Net 3.5 SP1 Dynamic Data
ASP.Net 3.5 SP1 Dynamic Data
 
DOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A RideDOSUG Taking Apache Camel For A Ride
DOSUG Taking Apache Camel For A Ride
 
Simplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a VengeanceSimplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a Vengeance
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.js
 
So you want to build a facebook App ?
So you want to build a facebook App ?So you want to build a facebook App ?
So you want to build a facebook App ?
 
Implementation of GUI Framework part3
Implementation of GUI Framework part3Implementation of GUI Framework part3
Implementation of GUI Framework part3
 
Web-First Design Patterns
Web-First Design PatternsWeb-First Design Patterns
Web-First Design Patterns
 
Taking Apache Camel For A Ride
Taking Apache Camel For A RideTaking Apache Camel For A Ride
Taking Apache Camel For A Ride
 
Web applications with Catalyst
Web applications with CatalystWeb applications with Catalyst
Web applications with Catalyst
 
Spring-training-in-bangalore
Spring-training-in-bangaloreSpring-training-in-bangalore
Spring-training-in-bangalore
 
Drupalcon 2023 - How Drupal builds your pages.pdf
Drupalcon 2023 - How Drupal builds your pages.pdfDrupalcon 2023 - How Drupal builds your pages.pdf
Drupalcon 2023 - How Drupal builds your pages.pdf
 
2023 - Drupalcon - How Drupal builds your pages
2023 - Drupalcon - How Drupal builds your pages2023 - Drupalcon - How Drupal builds your pages
2023 - Drupalcon - How Drupal builds your pages
 
GHC Participant Training
GHC Participant TrainingGHC Participant Training
GHC Participant Training
 
Acceptance Testing with Webrat
Acceptance Testing with WebratAcceptance Testing with Webrat
Acceptance Testing with Webrat
 
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember DataIn The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
 

Mehr von Jesse Cai

程序员0806期敏捷与性能的博弈
程序员0806期敏捷与性能的博弈程序员0806期敏捷与性能的博弈
程序员0806期敏捷与性能的博弈Jesse Cai
 
Status Ruby on Rails in China
Status Ruby on Rails in ChinaStatus Ruby on Rails in China
Status Ruby on Rails in ChinaJesse Cai
 
Ruby_Coding_Convention
Ruby_Coding_ConventionRuby_Coding_Convention
Ruby_Coding_ConventionJesse Cai
 
Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)Jesse Cai
 
Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)Jesse Cai
 
Chinaonrails Rubyonrails21 Zh
Chinaonrails Rubyonrails21 ZhChinaonrails Rubyonrails21 Zh
Chinaonrails Rubyonrails21 ZhJesse Cai
 
1st Chinaonrails Open Course 开源实践
1st Chinaonrails Open Course 开源实践1st Chinaonrails Open Course 开源实践
1st Chinaonrails Open Course 开源实践Jesse Cai
 
1st Chinaonrails Open Course 高级战略
1st Chinaonrails Open Course 高级战略1st Chinaonrails Open Course 高级战略
1st Chinaonrails Open Course 高级战略Jesse Cai
 
Collaboration On Rails
Collaboration On RailsCollaboration On Rails
Collaboration On RailsJesse Cai
 
1st Chinaonrails Open Course 初试牛刀
1st Chinaonrails Open Course 初试牛刀1st Chinaonrails Open Course 初试牛刀
1st Chinaonrails Open Course 初试牛刀Jesse Cai
 

Mehr von Jesse Cai (10)

程序员0806期敏捷与性能的博弈
程序员0806期敏捷与性能的博弈程序员0806期敏捷与性能的博弈
程序员0806期敏捷与性能的博弈
 
Status Ruby on Rails in China
Status Ruby on Rails in ChinaStatus Ruby on Rails in China
Status Ruby on Rails in China
 
Ruby_Coding_Convention
Ruby_Coding_ConventionRuby_Coding_Convention
Ruby_Coding_Convention
 
Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)
 
Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)Analytics Uibbs 20080709 20080709 (Dashboard Report)
Analytics Uibbs 20080709 20080709 (Dashboard Report)
 
Chinaonrails Rubyonrails21 Zh
Chinaonrails Rubyonrails21 ZhChinaonrails Rubyonrails21 Zh
Chinaonrails Rubyonrails21 Zh
 
1st Chinaonrails Open Course 开源实践
1st Chinaonrails Open Course 开源实践1st Chinaonrails Open Course 开源实践
1st Chinaonrails Open Course 开源实践
 
1st Chinaonrails Open Course 高级战略
1st Chinaonrails Open Course 高级战略1st Chinaonrails Open Course 高级战略
1st Chinaonrails Open Course 高级战略
 
Collaboration On Rails
Collaboration On RailsCollaboration On Rails
Collaboration On Rails
 
1st Chinaonrails Open Course 初试牛刀
1st Chinaonrails Open Course 初试牛刀1st Chinaonrails Open Course 初试牛刀
1st Chinaonrails Open Course 初试牛刀
 

Kürzlich hochgeladen

Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 

Kürzlich hochgeladen (20)

Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 

Apachecon Rails

  • 1. Cheap, Fast, and Good You can have it all with Ruby on Rails Brian McCallister brianm@chariotsolutions.com http://www.chariotsolutions.com/ (c) 2005, Brian McCallister
  • 2. What is Ruby? • Dynamic and Interpreted • Strong support for OO programming • Everything is an object ( 2.next == 3 ) • Strong support for functional-style programming • Blocks, closures, first-class functions • Child of Perl and Smalltalk (c) 2005, Brian McCallister
  • 3. What is Rails? • Model-2 Web Framework • Object/Relational Mapping Library • SOAP Producer/Consumer Framework • Email Templating/Mailing Library • Code Generator • Very Rapidly Evolving! (c) 2005, Brian McCallister
  • 4. Principles Involved • Less Code • Convention over Configuration • Proximity • Least Surprise • Make components play nicely together! (c) 2005, Brian McCallister
  • 5. Action Pack That Web Stuff (c) 2005, Brian McCallister
  • 6. Request Cycle (c) 2005, Brian McCallister
  • 7. Some Code require 'date' class AggregateController < ApplicationController model :entry def for_date date = DateTime.parse @params[:date] logger.debug quot;for_date: #{date}quot; @entries = Entry.on_date date end # Additional actions removed for slide’s benefit` end (c) 2005, Brian McCallister
  • 8. Action require 'date' class AggregateController < ApplicationController model :entry Action def for_date date = DateTime.parse @params[:date] logger.debug quot;for_date: #{date}quot; @entries = Entry.on_date date end # Additional actions removed for slide’s benefit` end (c) 2005, Brian McCallister
  • 9. Controller Controller require 'date' class AggregateController < ApplicationController model :entry Action def for_date date = DateTime.parse @params[:date] logger.debug quot;for_date: #{date}quot; @entries = Entry.on_date date end Action def list_entries @entries = Entry.find_all end # Additional actions removed for slide’s benefit` end (c) 2005, Brian McCallister
  • 10. How We Got Here ActionController::Routing::Routes.draw do |map| # map.connect ':controller/service.wsdl', # :action => 'wsdl' map.connect 'wombat/is/friendly', :controller => :feeds, :action => :list map.connect '', :controller => :feeds, :action => :list # Default Route map.connect ':controller/:action/:id' end (c) 2005, Brian McCallister
  • 11. routes.rb ActionController::Routing::Routes.draw do |map| http://localhost/wombat/is/friendly # map.connect ':controller/service.wsdl', # :action => 'wsdl' map.connect 'wombat/is/friendly', :controller => :feeds, :action => :list map.connect '', :controller => :feeds, :action => :list # Default Route map.connect ':controller/:action/:id' end (c) 2005, Brian McCallister
  • 12. routes.rb ActionController::Routing::Routes.draw do |map| # map.connect ':controller/service.wsdl', # :action => 'wsdl' map.connect 'wombat/is/friendly', http://localhost/ :controller => :feeds, :action => :list map.connect '', :controller => :feeds, :action => :list # Default Route map.connect ':controller/:action/:id' end (c) 2005, Brian McCallister
  • 13. routes.rb ActionController::Routing::Routes.draw do |map| # map.connect ':controller/service.wsdl', # :action => 'wsdl' map.connect 'wombat/is/friendly', :controller => :feeds, :action => :list map.connect '', :controller => :feeds, http://localhost/feeds/list :action => :list # Default Route map.connect ':controller/:action/:id' end (c) 2005, Brian McCallister
  • 14. Show Us Something! <h1>Recent Stories...</h1> <table class=quot;entryTablequot; > <% for entry in @entries %> <tr> <td class=quot;entryTitlequot;> <%= entry.feed.title + quot;: quot; + entry.title %> </td> </tr> <tr> <td class=quot;entryBodyquot;> <%= entry.body %> </td> </tr> <% end %> </table> (c) 2005, Brian McCallister
  • 15. Directives <h1>Recent Stories...</h1> <table class=quot;entryTablequot; > <% for entry in @entries %> <tr> <td class=quot;entryTitlequot;> <%= entry.feed.title + quot;: quot; + entry.title %> </td> </tr> <tr> <td class=quot;entryBodyquot;> <%= entry.body %> </td> </tr> <% end %> </table> (c) 2005, Brian McCallister
  • 16. Expressions <h1>Recent Stories...</h1> <table class=quot;entryTablequot; > <% for entry in @entries %> <tr> <td class=quot;entryTitlequot;> <%= entry.feed.title + quot;: quot; + entry.title %> </td> </tr> <tr> <td class=quot;entryBodyquot;> <%= entry.body %> </td> </tr> <% end %> </table> (c) 2005, Brian McCallister
  • 17. Helpers & Partials <h1>Recent Stories...</h1> my_view.rhtml <%= render_partial quot;entry_listquot;, :stories => @entries %> <table class=quot;entryTablequot; > _entry_list.rhtml <% for entry in stories %> <tr> <td class=quot;entryTitlequot;> <%= entry.feed.title + quot;: quot; + entry.title %> </td> </tr> <tr> <td class=quot;entryBodyquot;> <%= entry.body %> </td> </tr> <% end %> </table> (c) 2005, Brian McCallister
  • 18. Helpers <h1>Recent Stories...</h1> my_view.rhtml <%= render_partial quot;entry_listquot;, :stories => @entries %> <table class=quot;entryTablequot; > _entry_list.rhtml <% for entry in stories %> <tr> <td class=quot;entryTitlequot;> <%= entry.feed.title + quot;: quot; + entry.title %> </td> </tr> <tr> <td class=quot;entryBodyquot;> <%= entry.body %> </td> </tr> <% end %> </table> (c) 2005, Brian McCallister
  • 19. Parameterized Partials <h1>Recent Stories...</h1> my_view.rhtml <%= render_partial quot;entry_listquot;, :stories => @entries %> <table class=quot;entryTablequot; > _entry_list.rhtml <% for entry in stories %> <tr> <td class=quot;entryTitlequot;> <%= entry.feed.title + quot;: quot; + entry.title %> </td> </tr> <tr> <td class=quot;entryBodyquot;> <%= entry.body %> </td> </tr> <% end %> </table> (c) 2005, Brian McCallister
  • 20. Picking Views • Default Views • The View for that one over there... • Named Views • Something completely different? (c) 2005, Brian McCallister
  • 21. Default Views require 'date' class AggregateController < ApplicationController model :entry aggregate/for_date.rhtml def for_date date = DateTime.parse @params[:date] logger.debug quot;for_date: #{date}quot; @entries = Entry.on_date date end # Additional actions removed for slide’s benefit` end (c) 2005, Brian McCallister
  • 22. render_* require 'date' class AggregateController < ApplicationController model :entry def today @entries = Entry.on_date Date.today render_action :list_entries end aggregate/list_entries.rhtml def list_entries @entries = Entry.find_all end # Additional actions removed for slide’s benefit` end (c) 2005, Brian McCallister
  • 23. Named Views require 'date' class AggregateController < ApplicationController model :entry def another_one @entries = Entry.find_all render :a_template a_template.rhtml end # Additional actions removed for slide’s benefit` end (c) 2005, Brian McCallister
  • 24. Raw Rendering require 'date' class AggregateController < ApplicationController model :entry def direct_write render_text quot;Hello World!quot; end No template! # Additional actions removed for slide’s benefit` end (c) 2005, Brian McCallister
  • 25. Additional Options • send_data • send_file • render_to_string • render_nothing • render_text with a block • redirect_to • redirect_to_url • redirect_to_path • builders • and more! (c) 2005, Brian McCallister
  • 26. Helpers • Programmatic output generation • Global, Controller Specific, Importable • Like tag libraries • kind of • Lots of built-ins (c) 2005, Brian McCallister
  • 27. #{Controller}Helper module AggregateHelper def say_hello(name) Helper quot;<h1>Hello, #{name}quot; end end <h1>Recent Stories...</h1> Usage <%= say_hello quot;Brianquot; %> <table> <% for entry in @entries %> ... (c) 2005, Brian McCallister
  • 28. Rules, well Suggestions • #{Controller}Helper applied from matching Controller • ApplicationHelper available everywhere • Declare reliance on a specific Helper from any Controller • Rarely need to do this, though (c) 2005, Brian McCallister
  • 29. Action Pack Magic 3 • Controllers • Helpers • Views • Things not discussed: • Components • Caching • Filters (c) 2005, Brian McCallister
  • 30. Active Record You get the data from the database and shake it all about... (c) 2005, Brian McCallister
  • 31. Active Record Basics • Not Required! • One Row == One Instance • Dynamic Properties by Default • Query by SQL or Criteria • Including joins • PostgreSQL, MySQL, Oracle, DB2 ... more (c) 2005, Brian McCallister
  • 32. The Schema (c) 2005, Brian McCallister
  • 33. The Classes class Feed < ActiveRecord::Base has_many :entries validates_presence_of :title, :url end ... class Entry < ActiveRecord::Base belongs_to :feed validates_presence_of :title, :body, :entry_uid validates_uniqueness_of :entry_uid end (c) 2005, Brian McCallister
  • 34. Relations class Feed < ActiveRecord::Base has_many :entries validates_presence_of :title, :url end ... class Entry < ActiveRecord::Base belongs_to :feed validates_presence_of :title, :body, :entry_uid validates_uniqueness_of :entry_uid end (c) 2005, Brian McCallister
  • 35. Queries def Entry.recent(count) Entry.find :all, :order =>'created_on DESC', :limit => count, :include => [:feed] end def Entry.after(date) Entry.find :all, :conditions => ['created_on >= ?', date], :order => 'created_on DESC', :include => [:feed] end def Entry.before(date) Entry.find_by_sql [quot;select e.* from entries e where created_on < ?quot;, date] end (c) 2005, Brian McCallister
  • 36. Criteria def Entry.recent(count) Entry.find :all, :order =>'created_on DESC', :limit => count, :include => [:feed] end def Entry.after(date) Entry.find :all, :conditions => ['created_on >= ?', date], :order => 'created_on DESC', :include => [:feed] end def Entry.before(date) Entry.find_by_sql [quot;select e.* from entries e where created_on < ?quot;, date] end (c) 2005, Brian McCallister
  • 37. SQL def Entry.recent(count) Entry.find :all, :order =>'created_on DESC', :limit => count, :include => [:feed] end def Entry.after(date) Entry.find :all, :conditions => ['created_on >= ?', date], :order => 'created_on DESC', :include => [:feed] end def Entry.before(date) Entry.find_by_sql [quot;select e.* from entries e where created_on < ?quot;, date] end (c) 2005, Brian McCallister
  • 38. Code Generator This stuff rocks! (c) 2005, Brian McCallister
  • 39. Creating Rails Project brianm@kite:~/Sites$ rails apachecon create app create app/apis create app/controllers create app/helpers create app/models ... create log/test.log brianm@kite:~/Sites$ ls -F apachecon/ CHANGELOG Rakefile components/ db/ lib/ public/ test/ README app/ config/ doc/ log/ script/ vendor/ brianm@kite:~/Sites$ (c) 2005, Brian McCallister
  • 40. This Created... • Project Hierarchy • Config file (for database connection) • Rakefile (Makefile) • System Test Harness • Unit Test Harness • Apache HTTPD Configs (.htaccess) • Additional Code Generation Scripts... (c) 2005, Brian McCallister
  • 41. Configure Database brianm@kite:~/Sites/apachecon$ cat config/ database.yml development: adapter: postgresql database: ruby_blogs_dev host: localhost username: blogs password: ********** ... production: adapter: postgresql database: ruby_blogs host: localhost username: blogs password: ********** brianm@kite:~/Sites/apachecon$ (c) 2005, Brian McCallister
  • 42. Some CRUD brianm@kite:~/Sites/apachecon$ ./script/generate scaffold Talk dependency model exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/talk.rb create test/unit/talk_test.rb create test/fixtures/talks.yml exists app/controllers/ exists app/helpers/ create app/views/talks exists test/functional/ create app/controllers/talks_controller.rb create test/functional/talks_controller_test.rb create app/helpers/talks_helper.rb create app/views/layouts/talks.rhtml create public/stylesheets/scaffold.css create app/views/talks/list.rhtml create app/views/talks/show.rhtml create app/views/talks/new.rhtml create app/views/talks/edit.rhtml create app/views/talks/_form.rhtml brianm@kite:~/Sites/apachecon$ (c) 2005, Brian McCallister
  • 43. A Table apachecon=> create table talks ( id serial primary key, name varchar(255) not null, presenter varchar(255) not null, description text not null); NOTICE: CREATE TABLE will create implicit sequence quot;sessions_id_seqquot; for serial column quot;sessions.idquot; NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index quot;sessions_pkeyquot; for table quot;sessionsquot; CREATE TABLE apachecon=> (c) 2005, Brian McCallister
  • 44. Start the Server... brianm@kite:~/Sites/apachecon$ ./script/server => Rails application started on http://0.0.0.0:3000 [2005-05-25 18:00:12] INFO WEBrick 1.3.1 [2005-05-25 18:00:12] INFO ruby 1.8.2 (2004-12-25) [2005-05-25 18:00:12] INFO WEBrick::HTTPServer#start: pid=26996 port=3000 (c) 2005, Brian McCallister
  • 45. List (c) 2005, Brian McCallister
  • 46. TalksController class TalksController < ApplicationController def index list render_action 'list' end def list @talk_pages, @talks = paginate :talk, :per_page => 10 end def show @talk = Talk.find(@params[:id]) end ... end (c) 2005, Brian McCallister
  • 48. The Edit View <h1>Editing talk</h1> <%= start_form_tag :action => 'update', :id => @talk %> <%= render_partial quot;formquot; %> <%= submit_tag quot;Editquot; %> talks/edit.rhtml <%= end_form_tag %> <%= link_to 'Show', :action => 'show', :id => @talk %> | <%= link_to 'Back', :action => 'list' %> <%= error_messages_for 'talk' %> <!--[form:talk]--> <p><label for=quot;talk_descriptionquot;>Description</label><br/> <%= text_area 'talk', 'description' %></p> <p><label for=quot;talk_presenterquot;>Presenter</label><br/> <%= text_field 'talk', 'presenter' %></p> talks/_form.rhtml <p><label for=quot;talk_namequot;>Name</label><br/> <%= text_field 'talk', 'name' %></p> <!--[eoform:talk]--> (c) 2005, Brian McCallister
  • 49. List Again (c) 2005, Brian McCallister
  • 50. Unit and System Tests brianm@kite:~/Sites/apachecon$ rake (in /Users/brianm/Sites/apachecon) ruby -Ilib:test quot;/usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/ rake/rake_test_loader.rbquot; quot;test/unit/talk_test.rbquot; Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/ rake_test_loader Started . Finished in 0.11654 seconds. 1 tests, 1 assertions, 0 failures, 0 errors ruby -Ilib:test quot;/usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/ rake/rake_test_loader.rbquot; quot;test/functional/ talks_controller_test.rbquot; Loaded suite /usr/local/lib/ruby/gems/1.8/gems/rake-0.5.4/lib/rake/ rake_test_loader Started ........ Finished in 0.456943 seconds. 8 tests, 26 assertions, 0 failures, 0 errors brianm@kite:~/Sites/apachecon$ (c) 2005, Brian McCallister
  • 51. .htaccess # General Apache options AddHandler fastcgi-script .fcgi AddHandler cgi-script .cgi Options +FollowSymLinks +ExecCGI # If you don't want Rails to look in certain directories, # use the following rewrite rules so that Apache won't ... <snip /> # # Example: # RewriteCond %{REQUEST_URI} ^/notrails.* # RewriteRule .* - [L] # Redirect all requests not available on the filesystem to Rails # By default the cgi dispatcher is used which is very slow # # For better performance replace the dispatcher with the fastcgi one # # Example: # RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] RewriteEngine On RewriteRule ^$ index.html [QSA] RewriteRule ^([^.]+)$ $1.html [QSA] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ dispatch.cgi [QSA,L] ... (c) 2005, Brian McCallister
  • 52. Extensible Generator • Some 3rd Party Generators: • Login Generator • Salted Hash Login Generator • Tabbed Navbar Generator • Search Generator • Configuration Generator • Postback Generator (c) 2005, Brian McCallister
  • 53. Deployment Time Stuff to be aware of... (c) 2005, Brian McCallister
  • 54. Environment • Development • Test • Production (c) 2005, Brian McCallister
  • 55. Web Servers • Webrick • Apache Web Server • CGI • mod_ruby • fastcgi • lighttpd • fastcgi (c) 2005, Brian McCallister
  • 56. Session Storage • Serialize to /tmp • DRb Server • Database • memcached • Custom • No Sessions (c) 2005, Brian McCallister
  • 57. Scaling Up • Multi-processing model (like prefork) • DB Connection per FCGI Process • Remote FCGI instances • Static and Dynamic Caching • Easy to interface with C • (Almost as easy to interface with OCaml) (c) 2005, Brian McCallister
  • 58. The Diagram (c) 2005, Brian McCallister
  • 59. Web Resources • Ruby • http://www.ruby-lang.org/ • Why’s Poignant Guide to Ruby • http://poignantguide.net/ • Ruby on Rails • http://www.rubyonrails.com/ • Ruby Documentation • http://www.ruby-doc.org/ (c) 2005, Brian McCallister
  • 60. That’s all folks! Brian McCallister brianm@chariotsolutions.com http://www.chariotsolutions.com/