SlideShare a Scribd company logo
1 of 171
Download to read offline
{   Rails 3
Rails 3: Dashing to the Finish
Overview
Dashing to
the Finish
A Lot Like
Rails 2.3
Quick Refresher
What Hasn’t
 Changed?
MVC
REST
Resources
Controllers
Migrations
AR Ideas
Big User-Facing
   Changes
File Structure
con g.ru
# This file is used by Rack-based
# servers to start the application.
require ::File.expand_path(
  '../config/environment',
  __FILE__
)
run Tutorial::Application
con g/boot.rb
require 'rubygems'

# Set up gems listed in the Gemfile.
gemfile = File.expand_path(
  '../../Gemfile',
  __FILE__
)
if File.exist?(gemfile)
  ENV['BUNDLE_GEMFILE'] = gemfile
  require 'bundler'
  Bundler.setup
end
Gem le
source 'http://rubygems.org'

gem 'rails', '3.0.0.beta3'
gem 'sqlite3-ruby'
con g/environment.rb
# Load the rails application
require File.expand_path(
  '../application',
  __FILE__
)

# Initialize the rails application
Tutorial::Application.initialize!
con g/application.rb (1)
require File.expand_path(
  '../boot',
  __FILE__
)

require 'rails/all'

if defined?(Bundler)
  Bundler.require(:default, Rails.env)
end
con g/application.rb (2)
module Tutorial
  class Application < Rails::Application
    config.encoding = "utf-8"
    config.filter_parameters +=
      [:password]
  end
end
environments/production.rb
Tutorial::Application.configure do
  config.cache_classes = true
  config.consider_all_requests_local = false
  config.action_controller.perform_caching = true
  config.action_dispatch.x_sendfile_header = "X-Sendfile"
  config.serve_static_assets = false
end
initializers/session_store.rb
Rails.application.
  config.session_store(
    :cookie_store,
    :key => '_tutorial_session'
  )
script/rails (1)
#!/usr/bin/env ruby
# This command will automatically
# be run when you run "rails" with
# Rails 3 gems installed from the
# root of your application.

ENV_PATH = File.expand_path(
  '../../config/environment',
  __FILE__
)
script/rails (2)
BOOT_PATH = File.expand_path(
  '../../config/boot',
  __FILE__
)

APP_PATH = File.expand_path(
  '../../config/application',
  __FILE__
)

require BOOT_PATH
require 'rails/commands'
Recent
Even Easier to
  Remove
   Bundler
Removing Bundler
$ rm Gemfile
app/mailers
$ script/rails g mailer welcome
  create app/mailers/welcome.rb
  invoke erb
  create    app/views/welcome
  invoke test_unit
  create    test/functional/welcome_test.rb
app/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Tutorial</title>
    <%= stylesheet_link_tag :all %>
    <%= javascript_include_tag :defaults %>
    <%= csrf_meta_tag %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>
public/
javascripts/
   rails.js
github.com/
rails/jquery-ujs
db/seeds.rb
rake db:setup
db:create
db:schema:load
    db:seed
lib/tasks/setup.rake
task :bundle do
  system "bundle install"
end

task :setup => ["bundle", "db:setup"]
Rails Command

★ generate   | g   ★ destroy
★ console    | c   ★ benchmarker
★ server     | s   ★ profiler
★ dbconsole | db   ★ plugin
★ application      ★ runner
Block Helpers
Block Helpers (Before)
<% form_for @post do |f| %>
  <%= f.input_field :name %>
<% end %>
Block Helpers (Before)
<% box do %>
  <p>Hello World!</p>
<% end %>
Block Helpers (Before)
def box(&block)
  content = "<div class='box'>" <<
  capture(&block) << "</div>"

  if block_called_from_erb?
    concat(content)
  else
    content
  end
end
Block Helpers (After)
<%= box do %>
  <p>Hello World!</p>
<% end %>
Block Helpers (After)
def box(&block)
  "<div class='box'>" 
  "#{capture(&block)}" 
  "</div>"
end
Block Helpers (After)
def box(&block)
  "<div class='box'>" 
  "#{capture(&block)}" 
  "</div>".html_safe
end
Recent
Tons of Fixes to
   XSS Safe
Lots of XSS-
  Related
Changes to
Your App...
You’re Doing it
    Wrong
Router
Note:
  Signi cant
Changes Ahead
Also Note:
 Old Mapper
Still Available
Matching
map.connect "posts",
  :controller => :posts,
  :action => :index
Matching
map.connect "posts",
  :controller => :posts,
  :action => :index

match "posts" => "posts#index"
Optional Segments
match "/posts(/page)" => "posts#index"
Optional Dynamic Segments
match "/posts(/:id)" => "posts#index"
Default Parameters
match "/posts(/:id)" => "posts#index",
      :defaults => {:id => 1}
Default Parameters
match "/posts(/:id)" => "posts#index",
      :id => 1
Named Routes
match "/posts(/:id)" => "posts#index",
      :id => 1,
      :as => "posts"
The Root
root :to => "posts#index"
Scopes
Path Scope
match "/admin/posts" => "posts#index"
match "/admin/users" => "users#index"
Path Scope
match "/admin/posts" => "posts#index"
match "/admin/users" => "users#index"

scope :path => "admin" do
  match "/posts" => "posts#index"
  match "/users" => "users#index"
end
Path Scope
match "/admin/posts" => "posts#index"
match "/admin/users" => "users#index"

scope "admin" do
  match "/posts" => "posts#index"
  match "/users" => "users#index"
end
Module Scope
match "/posts" => "admin/posts#index"
match "/users" => "admin/users#index"
Module Scope
match "/posts" => "admin/posts#index"
match "/users" => "admin/users#index"

scope :module => "admin" do
  match "/posts" => "posts#index"
  match "/users" => "users#index"
end
Both
match "admin/posts" => "admin/posts#index"
match "admin/users" => "admin/users#index"
Both
match "admin/posts" => "admin/posts#index"
match "admin/users" => "admin/users#index"

namespace "admin" do
  match "/posts" => "posts#index"
  match "/users" => "users#index"
end
HTTP Methods
Get Request
match "/posts" => "posts#index",
      :via => "get"
Get Request
match "/posts" => "posts#index",
      :via => "get"

get "/posts" => "posts#index"
Scoping
scope "/posts" do
  controller :posts do
    get "/" => :index
  end
end
Scoping
scope "/posts" do
  controller :posts do
    get "/" => :index
  end
end

get "/posts" => "posts#index"
Default Resource Route
controller :posts do
  scope "/posts" do
    get    "/"           =>   :index
    post   "/"           =>   :create
    get    "/:id"        =>   :show
    put    "/:id"        =>   :update
    delete "/:id"        =>   :delete
    get    "/new"        =>   :new
    get    "/:id/edit"   =>   :edit
  end
end
Default Resource Route
controller :posts do
  scope "/posts" do
    get    "/"           =>   :index,   :as => :posts
    post   "/"           =>   :create
    get    "/:id"        =>   :show,    :as => :post
    put    "/:id"        =>   :update
    delete "/:id"        =>   :delete
    get    "/new"        =>   :new,     :as => :new_post
    get    "/:id/edit"   =>   :edit,    :as => :edit_post
  end
end
Constraints
Regex Constraint
get "/:id" => "posts#index",
  :constraints => {:id => /d+/}
Regex Constraint
get "/:id" => "posts#index",
  :id => /d+/
Request-Based Constraint
get "/mobile" => "posts#index",
  :constraints => {:user_agent => /iPhone/}
Request-Based Constraint
get "/mobile" => "posts#index",
  :constraints => {:user_agent => /iPhone/},
  :defaults    => {:mobile      => true}
Request-Based Constraint
get "/mobile" => "posts#index",
  :user_agent => /iPhone/,
  :mobile     => true
Object Constraints
class DubDubConstraint
  def self.matches?(request)
    request.host =~ /^(www.)/
  end
end

get "/" => "posts#index",
    :constraints => DubDubConstraint
Rack
Equivalent
get "/posts" => "posts#index"
Equivalent
get "/posts" => "posts#index"

get "/posts" =>
    PostsController.action(:index)
Rack
>> a = PostsController.action(:index)
Rack
>> a = PostsController.action(:index)
=> #<Proc:0x0000000103d050d0@/Users/
wycats/Code/rails/actionpack/lib/
action_controller/metal.rb:123>
Rack
>> a = PostsController.action(:index)
=> #<Proc:0x0000000103d050d0@/Users/
wycats/Code/rails/actionpack/lib/
action_controller/metal.rb:123>
>> e = Rack::MockRequest.env_for("/")
Rack
>> a = PostsController.action(:index)
=> #<Proc:0x0000000103d050d0@/Users/
wycats/Code/rails/actionpack/lib/
action_controller/metal.rb:123>
>> e = Rack::MockRequest.env_for("/")
=> {"SERVER_NAME"=>"example.org",
"CONTENT_LENGTH"=>"0", ...}
Rack
>> a = PostsController.action(:index)
=> #<Proc:0x0000000103d050d0@/Users/
wycats/Code/rails/actionpack/lib/
action_controller/metal.rb:123>
>> e = Rack::MockRequest.env_for("/")
=> {"SERVER_NAME"=>"example.org",
"CONTENT_LENGTH"=>"0", ...}
>> e.call(a)
Rack
>> a = PostsController.action(:index)
=> #<Proc:0x0000000103d050d0@/Users/
wycats/Code/rails/actionpack/lib/
action_controller/metal.rb:123>
>> e = Rack::MockRequest.env_for("/")
=> {"SERVER_NAME"=>"example.org",
"CONTENT_LENGTH"=>"0", ...}
>> e.call(a)
=> [200, {"ETag"=>
    '"eca5953f36da05ff351d712d904e"',
    ...},
    ["Hello World"]]
Match to Rack
class MyApp
  def call(env)
    [200,
      {"Content-Type" => "text/html"},
      ["Hello World"]]
  end
end

get "/" => MyApp.new
Redirection
get "/" => redirect("/foo")
Redirection
get "/" => redirect("/foo")

get "/:id" => redirect("/posts/%{id}")
get "/:id" => redirect("/posts/%s")
Redirection
get "/" => redirect("/foo")

get "/:id" => redirect("/posts/%{id}")
get "/:id" => redirect("/posts/%s")

get "/:id" => redirect { |params, req|
  ...
}
Rack App
def redirect(*args, &block)
  options = args.last.is_a?(Hash) ? args.pop : {}

  path        =   args.shift || block
  path_proc   =   path.is_a?(Proc) ? path : proc { |params| path % params }
  status      =   options[:status] || 301
  body        =   'Moved Permanently'

  lambda do |env|
    req = Request.new(env)

    params = [req.symbolized_path_parameters]
    params << req if path_proc.arity > 1

    uri = URI.parse(path_proc.call(*params))
    uri.scheme ||= req.scheme
    uri.host   ||= req.host
    uri.port   ||= req.port unless req.port == 80

    headers = {
      'Location' => uri.to_s,
      'Content-Type' => 'text/html',
      'Content-Length' => body.length.to_s
    }
    [ status, headers, [body] ]
  end
end
Rack App
def redirect(*args, &block)
  options = args.last.is_a?(Hash) ? args.pop : {}

  path        =   args.shift || block
  path_proc   =   path.is_a?(Proc) ? path : proc { |params| path % params }
  status      =   options[:status] || 301
  body        =   'Moved Permanently'

  lambda do |env|
    req = Request.new(env)

    redirect(*args, &block)
    params = [req.symbolized_path_parameters]
    params << req if path_proc.arity > 1

    uri = URI.parse(path_proc.call(*params))
    uri.scheme ||= req.scheme
    uri.host   ||= req.host
    uri.port   ||= req.port unless req.port == 80

    headers = {
      'Location' => uri.to_s,
      'Content-Type' => 'text/html',
      'Content-Length' => body.length.to_s
    }
    [ status, headers, [body] ]
  end
end
Rack App
lambda do |env|
  req = Request.new(env)

  params = [req.symbolized_path_parameters]
  params << req if path_proc.arity > 1

  uri = URI.parse(path_proc.call(*params))
  uri.scheme ||= req.scheme
  uri.host   ||= req.host
  uri.port   ||= req.port unless req.port == 80

  headers = {
    'Location' => uri.to_s,
    'Content-Type' => 'text/html',
    'Content-Length' => body.length.to_s
  }
  [ status, headers, [body] ]
end
Rack App
lambda do |env|
  req = Request.new(env)

  params = [req.symbolized_path_parameters]
  params << req if path_proc.arity > 1

  uri = URI.parse(path_proc.call(*params))
   [ status, headers, [body] ]
  uri.scheme ||= req.scheme
  uri.host   ||= req.host
  uri.port   ||= req.port unless req.port == 80

  headers = {
    'Location' => uri.to_s,
    'Content-Type' => 'text/html',
    'Content-Length' => body.length.to_s
  }
  [ status, headers, [body] ]
end
Resources
Resources
resources :magazines do
  resources :ads
end
Member Resources
resources :photos do
  member do
    get :preview
    get :print
  end
end
One-Offs
resources :photos do
  get :preview, :on => :member
end
Collections
resources :photos do
  collection do
    get :search
  end
end
Combination
scope :module => "admin" do
  constraints IpBlacklist do
    resources :posts, :comments
  end
end
Recent
#mount
Rack Endpoint
class MountedEndpoint
  def call(env)
    head = {"Content-Type" => "text/html"}
    body = "script: #{env["SCRIPT_NAME"]}"
    body += "path:   #{env["PATH_INFO"]}"
    [200, head, [body]]
  end
end
Mounting
class MountedEndpoint
  def call(env)
    head = {"Content-Type" => "text/html"}
    body = "script: #{env["SCRIPT_NAME"]}"
    body += "path:   #{env["PATH_INFO"]}"
    [200, head, [body]]
  end
end

mount "/end", :at => MountedEndpoint.new
Mounting
class MountedEndpoint
  def call(env)
    head = {"Content-Type" => "text/html"}
    body = "script: #{env["SCRIPT_NAME"]}"
    body += "path:   #{env["PATH_INFO"]}"
    [200, head, [body]]
  end
end

mount "/end", :at => MountedEndpoint.new

# "/end/point" =>
#   script: /end
#   path:   /point
Sinatra!
ActiveRecord
New Chainable,
  Lazy API
Chainable Methods

★ select        ★ order
★ from          ★ limit
★ where         ★ offset
★ joins         ★ includes
★ having        ★ lock
★ group         ★ readonly
Controller
def index
  @posts = Post.
    where(:published => true).
    order("publish_date desc")
end
Model
def index
  @posts = Post.published
end

class Post < ActiveRecord::Base
  scope :published,
    where(:published => true).
    order("publish_date desc")
end
Model
class Post < ActiveRecord::Base
  scope :desc,
    order("publish_date desc")

  scope :published,
    where(:published => true).desc
end
Controller
def index
  @posts = Post.
    where("created_at < ?", Time.now).
    order("publish_date desc")
end
Controller
def index
  @posts = Post.past
end

class Post < ActiveRecord::Base
  scope :desc,
    order("publish_date desc")

  def self.past
    where("created_at < ?",
      Time.now).desc
  end
end
Model
class Post < ActiveRecord::Base
  scope :desc,
    order("publish_date desc")

 def self.past
   where("created_at < ?",
   Time.now).desc
 end

  def self.recent(number)
    past.limit(5)
  end
end
Pagination
class PostsController < ApplicationController
  def index
    @posts = Posts.page(5, :per_page => 10)
  end
end

class Post < ActiveRecord::Base
  def self.page(number, options)
    per_page = options[:per_page]
    offset(per_page * (number - 1)).
      limit(per_page)
  end
end
named_scope

with_scope

   nd(:all)
scope
ActionMailer
Massive API
 Overhaul
Sending Emails
def welcome(user)
  @user = user
  mail(:to => user.email,
       :subject => "Welcome man!")
end
welcome.text.erb

welcome.html.erb
Layouts
layout "rails_dispatch"

def welcome(user)
  @user = user
  mail(:to => user.email,
       :subject => "Welcome man!")
end
rails_dispatch.text.erb

rails_dispatch.html.erb
Be More Speci c
def welcome(user)
  @user = user
  mail(:to => user.email,
    :subject => "Welcome man!") do |format|
    format.html
    format.text { render "generic" }
  end
end
Defaults
default :from => "wycats@gmail.com"

def welcome(user)
  @user = user
  mail(:to => user.email,
    :subject => "Welcome man!") do |format|
    format.html
    format.text { render "generic" }
  end
end
Attachments
def welcome(user)
  @user = user
  file = Rails.public_path.join("hello.pdf")
  contents = File.read(file)
  attachments["welcome.pdf"] = contents
  mail(:to => user.email,
    :subject => "Welcome man!")
end
Interceptors
class MyInterceptor
  def self.delivering_email(mail)
    original = mail.to
    mail.to = "wycats@gmail.com"
    mail.subject =
      "#{original}: #{mail.subject}"
  end
end
Interceptors
class MyInterceptor
  def self.delivering_email(mail)
    original = mail.to
    mail.to = "wycats@gmail.com"
    mail.subject =
      "#{original}: #{mail.subject}"
  end
end

config.action_mailer.
  register_interceptor(MyInterceptor)
Interceptors

 Delivery

 Observers
delivering_mail

    deliver

delivered_mail
Bundler
bundle install
bundle lock
bundle lock
.gitignore

.dot les
Engine Yard
  Heroku
   chef
Engine Yard
  Heroku
   chef
capistrano?
gembundler.com
gembundler.com
  /rails3.html
railsdispatch.com
 /posts/bundler
yehudakatz.com/
2010/04/12/some-of-
   the-problems-
   bundler-solves/
yehudakatz.com/
2010/04/17/ruby-
 require-order-
   problems/
Choices
rspec-rails
generators

    rake tasks

controller_example

  view_example

request_example

 mailer_example
Mailer Generator
$ script/rails g mailer welcome
  create app/mailers/welcome.rb
  invoke erb
  create    app/views/welcome
  invoke rspec
  create    spec/mailers/welcome_spec.rb
dm-rails
generators

      rake tasks

append_info_to_payload

      i18n_scope

IdentityMap middleware
generate a resource
$ rails g resource comment
  invoke data_mapper
  create    app/models/comment.rb
  invoke    test_unit
  create      test/unit/comment_test.rb
  create      test/fixtures/comments.yml
  invoke controller
  create    app/controllers/comments_controller.rb
  invoke    erb
  create      app/views/commentses
  invoke    test_unit
  create      test/functional/comments_controller_test.rb
  invoke    helper
  create      app/helpers/commentses_helper.rb
  invoke      test_unit
  create        test/unit/helpers/comments_helper_test.rb
  route resources :commentses
generate a resource
$ rails g resource comment
  invoke data_mapper
  create    app/models/comment.rb
  invoke    rspec
  create      spec/models/comment_spec.rb
  invoke controller
  create    app/controllers/comments_controller.rb
  invoke    erb
  create      app/views/comments
  invoke    rspec
  create      spec/controllers/comments_controller_spec.rb
  create      spec/views/comments
  invoke    helper
  create      app/helpers/comments_helper.rb
  invoke      rspec
  route resources :comments
rails g
$ rails g       Rails:
                  controller
                  generator
                  helper
                  integration_test
                  mailer
                  metal
                  migration
                  model
                  observer
                  performance_test
                  plugin
                  resource
                  scaffold
                  scaffold_controller
                  session_migration
                  stylesheets
What Else?
Ruby 1.9
Encoding
Mission
You Can
Assume UTF-8
Inside of Rails
(unless you
want to handle
  encodings
   yourself)
Testing
RSpec Driven
   Effort
Rails Testing
  Support
 Becomes
 Modular
ActionController Middleware
class PostsController
  use MyMiddleware, :only => :index
end
Metal
 becomes
AC::Metal
Rails 3: Dashing to the Finish
i18n
 Check Out Sven’s Talk

 Last slot in conference
Trimming
ActiveSupport
Dependencies
Thanks!
Questions?

More Related Content

What's hot

Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
Caldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW WorkshopCaldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW WorkshopCalderaLearn
 
The effective use of Django ORM
The effective use of Django ORMThe effective use of Django ORM
The effective use of Django ORMYaroslav Muravskyi
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersCaldera Labs
 
jQuery 1.7 Events
jQuery 1.7 EventsjQuery 1.7 Events
jQuery 1.7 Eventsdmethvin
 
Rails 3 Beautiful Code
Rails 3 Beautiful CodeRails 3 Beautiful Code
Rails 3 Beautiful CodeGreggPollack
 
jQuery Performance Tips and Tricks (2011)
jQuery Performance Tips and Tricks (2011)jQuery Performance Tips and Tricks (2011)
jQuery Performance Tips and Tricks (2011)Addy Osmani
 
Django - 次の一歩 gumiStudy#3
Django - 次の一歩 gumiStudy#3Django - 次の一歩 gumiStudy#3
Django - 次の一歩 gumiStudy#3makoto tsuyuki
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgetsvelveeta_512
 
jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009Remy Sharp
 
Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOdoo
 
ActiveResource & REST
ActiveResource & RESTActiveResource & REST
ActiveResource & RESTRobbert
 
History of jQuery
History of jQueryHistory of jQuery
History of jQueryjeresig
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gearsdion
 

What's hot (20)

Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Drupal, meet Assetic
Drupal, meet AsseticDrupal, meet Assetic
Drupal, meet Assetic
 
Caldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW WorkshopCaldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW Workshop
 
The effective use of Django ORM
The effective use of Django ORMThe effective use of Django ORM
The effective use of Django ORM
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress Developers
 
jQuery Essentials
jQuery EssentialsjQuery Essentials
jQuery Essentials
 
jQuery 1.7 Events
jQuery 1.7 EventsjQuery 1.7 Events
jQuery 1.7 Events
 
Rails 3 Beautiful Code
Rails 3 Beautiful CodeRails 3 Beautiful Code
Rails 3 Beautiful Code
 
jQuery Performance Tips and Tricks (2011)
jQuery Performance Tips and Tricks (2011)jQuery Performance Tips and Tricks (2011)
jQuery Performance Tips and Tricks (2011)
 
Django - 次の一歩 gumiStudy#3
Django - 次の一歩 gumiStudy#3Django - 次の一歩 gumiStudy#3
Django - 次の一歩 gumiStudy#3
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
jQuery basics
jQuery basicsjQuery basics
jQuery basics
 
jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009
 
Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI Framework
 
FuncUnit
FuncUnitFuncUnit
FuncUnit
 
Sane Async Patterns
Sane Async PatternsSane Async Patterns
Sane Async Patterns
 
ActiveResource & REST
ActiveResource & RESTActiveResource & REST
ActiveResource & REST
 
Django
DjangoDjango
Django
 
History of jQuery
History of jQueryHistory of jQuery
History of jQuery
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 

Similar to Rails 3: Dashing to the Finish

浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編Masakuni Kato
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On RailsJohn Wilker
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Joao Lucas Santana
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesLindsay Holmwood
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkBen Scofield
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportBen Scofield
 
QConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações WebQConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações WebFabio Akita
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - IntroductionVagmi Mudumbai
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)James Titcumb
 
Angular.js Fundamentals
Angular.js FundamentalsAngular.js Fundamentals
Angular.js FundamentalsMark
 
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
 
Using and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareUsing and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareAlona Mekhovova
 
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)James Titcumb
 
Rails 3 (beta) Roundup
Rails 3 (beta) RoundupRails 3 (beta) Roundup
Rails 3 (beta) RoundupWayne Carter
 

Similar to Rails 3: Dashing to the Finish (20)

Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On Rails
 
实战Ecos
实战Ecos实战Ecos
实战Ecos
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websites
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
QConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações WebQConSP 2015 - Dicas de Performance para Aplicações Web
QConSP 2015 - Dicas de Performance para Aplicações Web
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Angular.js Fundamentals
Angular.js FundamentalsAngular.js Fundamentals
Angular.js Fundamentals
 
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
 
Using and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareUsing and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middleware
 
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
 
Rails 3 (beta) Roundup
Rails 3 (beta) RoundupRails 3 (beta) Roundup
Rails 3 (beta) Roundup
 

More from Yehuda Katz

Writing Fast Client-Side Code: Lessons Learned from SproutCore
Writing Fast Client-Side Code: Lessons Learned from SproutCoreWriting Fast Client-Side Code: Lessons Learned from SproutCore
Writing Fast Client-Side Code: Lessons Learned from SproutCoreYehuda Katz
 
SproutCore: Amber
SproutCore: AmberSproutCore: Amber
SproutCore: AmberYehuda Katz
 
Organizing jQuery Projects Without OO
Organizing jQuery Projects Without OOOrganizing jQuery Projects Without OO
Organizing jQuery Projects Without OOYehuda Katz
 
Why You Shouldn't Write OO
Why You Shouldn't Write OO Why You Shouldn't Write OO
Why You Shouldn't Write OO Yehuda Katz
 
Making your oss project more like rails
Making your oss project more like railsMaking your oss project more like rails
Making your oss project more like railsYehuda Katz
 
Vaporware To Awesome
Vaporware To AwesomeVaporware To Awesome
Vaporware To AwesomeYehuda Katz
 
Merb Day Keynote
Merb Day KeynoteMerb Day Keynote
Merb Day KeynoteYehuda Katz
 
Merb Camp Keynote
Merb Camp KeynoteMerb Camp Keynote
Merb Camp KeynoteYehuda Katz
 
jQuery and Ruby Web Frameworks
jQuery and Ruby Web FrameworksjQuery and Ruby Web Frameworks
jQuery and Ruby Web FrameworksYehuda Katz
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersYehuda Katz
 

More from Yehuda Katz (14)

Writing Fast Client-Side Code: Lessons Learned from SproutCore
Writing Fast Client-Side Code: Lessons Learned from SproutCoreWriting Fast Client-Side Code: Lessons Learned from SproutCore
Writing Fast Client-Side Code: Lessons Learned from SproutCore
 
SproutCore: Amber
SproutCore: AmberSproutCore: Amber
SproutCore: Amber
 
Organizing jQuery Projects Without OO
Organizing jQuery Projects Without OOOrganizing jQuery Projects Without OO
Organizing jQuery Projects Without OO
 
Why You Shouldn't Write OO
Why You Shouldn't Write OO Why You Shouldn't Write OO
Why You Shouldn't Write OO
 
Making your oss project more like rails
Making your oss project more like railsMaking your oss project more like rails
Making your oss project more like rails
 
Vaporware To Awesome
Vaporware To AwesomeVaporware To Awesome
Vaporware To Awesome
 
Merb Day Keynote
Merb Day KeynoteMerb Day Keynote
Merb Day Keynote
 
Testing Merb
Testing MerbTesting Merb
Testing Merb
 
Merb jQuery
Merb jQueryMerb jQuery
Merb jQuery
 
Merb Camp Keynote
Merb Camp KeynoteMerb Camp Keynote
Merb Camp Keynote
 
Merb
MerbMerb
Merb
 
DataMapper
DataMapperDataMapper
DataMapper
 
jQuery and Ruby Web Frameworks
jQuery and Ruby Web FrameworksjQuery and Ruby Web Frameworks
jQuery and Ruby Web Frameworks
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails Developers
 

Recently uploaded

Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxMatsuo Lab
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintMahmoud Rabie
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsSafe Software
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaborationbruanjhuli
 
OpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureOpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureEric D. Schabell
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024D Cloud Solutions
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-pyJamie (Taka) Wang
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationIES VE
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfJamie (Taka) Wang
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.YounusS2
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfDaniel Santiago Silva Capera
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopBachir Benyammi
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IES VE
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 

Recently uploaded (20)

Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership Blueprint
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
 
OpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureOpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability Adventure
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-py
 
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve DecarbonizationUsing IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
Using IESVE for Loads, Sizing and Heat Pump Modeling to Achieve Decarbonization
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
activity_diagram_combine_v4_20190827.pdfactivity_diagram_combine_v4_20190827.pdf
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 Workshop
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 

Rails 3: Dashing to the Finish