7. DHH introduced Rails 3 at last RailsConf. He
likes whoppers. I actually hate burger king
entirely. I’m not sure how anybody can eat
there. But that’s OK, because I can make my
own rails burger the way I like
Rails 3: Tasty Burgers
Friday, May 7, 2010
10. A lot like Rails 2.3
We tried really hard to not break any 2.x APIs
unless it was really deemed necessary or a big
win.
Friday, May 7, 2010
11. Only surface level stuff is the same. A lot under the hood has
changed and there are a lot more features. I obviously can’t
cover everything in depth in an hour, so I’m going to gloss
over a lot and you can all look into details later.
But not really...
Friday, May 7, 2010
15. The router / controller / ActiveRecord model is still
optimized for organizing your application in terms of
Resources
Resources
Friday, May 7, 2010
17. Some changes (Arel, query api - Not going to really cover this)
General ideas are the same
associations
ActiveRecord pattern
ActiveRecord
Friday, May 7, 2010
20. There were some t weaks to the default File structure,
mostly in the config directory.
This is what you get when you generate a new Rails 3
app
File structure
One big thing about Rails 3 is that the app
file structure is not sacred, it’s just a
convention, not obligation
Friday, May 7, 2010
21. config.ru
Rails 3 is pure Rack. When you start an app, it evaluates config.ru, which is a
rack convention. If this file is there, all rack compatible rack servers know
what to do.
Could putfile is used by Rack-based(could even put a
# This
middleware or whatever here servers
fullto start in this one file).
#
Rails app the application.
require ::File.expand_path(
'../config/environment', __FILE__)
run AwesomeBlog::Application
Who doesn’t know what Rack is?
Could put middleware or whatever here (could
even put a full Rails app in this one file).
Friday, May 7, 2010
22. config.ru
That’s specifically the line that rack is looking for.
The constant is a Rack app that encapsulates
#everything related to the entire rails application that
This file is used by Rack-based servers
#we’re building the application.
to start
require ::File.expand_path(
'../config/environment', __FILE__)
run AwesomeBlog::Application
Friday, May 7, 2010
23. config/application.rb
This is the file that defines the application object from the last slide.
require File.expand_path('../boot', __FILE__)
Let’s look at some key components
require 'rails/all'
Bundler.require(:default,
Rails.env) if defined?(Bundler)
module AwesomeBlog
class Application < Rails::Application
config.encoding = "utf-8"
config.filter_parameters += [:password]
end
end
Friday, May 7, 2010
24. config/application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(:default,
Rails.env) if defined?(Bundler)
module AwesomeBlog
class Application < Rails::Application
config.encoding = "utf-8"
config.filter_parameters += [:password]
end
end
Friday, May 7, 2010
25. config/application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(:default,
Rails.env) if defined?(Bundler)
module AwesomeBlog
class Application < Rails::Application
config.encoding = "utf-8"
config.filter_parameters += [:password]
end
end
Friday, May 7, 2010
26. config/application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(:default, A Rack App!
Rails.env) if defined?(Bundler)
module AwesomeBlog
class Application < Rails::Application
config.encoding = "utf-8"
config.filter_parameters += [:password]
end
end
Friday, May 7, 2010
27. Contains all application specific information. Takes the “in the
sky” constants / globals that were needed for a rails 2.3
application and encapsulates them.
Routes, Config, Middleware, Initializers
Application Object
One day, we’ll have many application objects in one
process.
Ruby summer of code project to get this done.
Friday, May 7, 2010
28. config/application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(:default,
Rails.env) if defined?(Bundler)
module AwesomeBlog
class Application < Rails::Application
config.encoding = "utf-8"
config.filter_parameters += [:password]
end
end
Friday, May 7, 2010
29. config/boot.rb
require 'rubygems'
# Set up gems listed in the Gemfile.
gemfile =
File.expand_path('../../Gemfile', __FILE__)
begin
ENV['BUNDLE_GEMFILE'] = gemfile
require 'bundler'
Bundler.setup
rescue Bundler::GemNotFound => e
STDERR.puts e.message
STDERR.puts "Try running `bundle install`."
exit!
end if File.exist?(gemfile)
Friday, May 7, 2010
30. config/boot.rb
require 'bundler'
Bundler.setup
Friday, May 7, 2010
31. Bundler is a tool we built to manage gem dependencies. As it turns out, as rails
applications grow, dependencies become painful to deal with.
Many years in the making. Many iterations. It grew out of projects that had many
complicate dependencies and it was basically impossible to deal with it all by hand
Friday, May 7, 2010
32. Gemfile
It all starts here. This file is located at the root of the application.
All gem dependencies will be listed here. So far our app is small, so we only depend
on rails itself (note the version is the one that we are currently working with)
and also we have a dependency on sqlite since that’s the database that we’re
using.
source 'http://rubygems.org'
gem 'rails', '3.0.0.beta3'
gem 'sqlite3-ruby', :require => 'sqlite3'
Friday, May 7, 2010
33. Step t wo is to run the “bundle install” command.
* Checks gems already on system
* Downloads what is missing
$ bundle install
Friday, May 7, 2010
35. What are the major wins that we get from using
bundler?
Wins:
Friday, May 7, 2010
36. Dependencies in applications will evolve a lot throughout
the life of an application
Ruby is maturing. There are a LOT of gems out there that
you’ll be wanting to use. Bundler makes doing it easy.
Easy to update dependencies
Friday, May 7, 2010
37. Gemfile
What happens if you want to update your application to
the latest version of rails?
source 'http://rubygems.org'
gem 'rails', '3.0.0.beta3'
gem 'sqlite3-ruby', :require => 'sqlite3'
Friday, May 7, 2010
38. Gemfile
You’re done. All child dependencies will be handled for you.
The same goes if you want to roll back to a previous version. Just
change the Gemfile
source 'http://rubygems.org'
gem 'rails', '3.0.0'
gem 'sqlite3-ruby', :require => 'sqlite3'
Friday, May 7, 2010
39. You know all your dependencies are accounted for and you won’t be
surprised when you deploy.
Bundler does not let you use a gem if it is not listed in the Gemfile.
So, you can’t accidentally forget to install a gem on the ser ver when
you deploy.
Isolation
Friday, May 7, 2010
40. Your Gemfile accounts for all gems. You share your app with other
developers. They run `bundle install` and they’re good to go.
Bundler tracks all child dependencies as well as top level app
dependencies
Sharing
Come back to a project 3 months later. What version of UUID
was I using? (yeah, that broke deploys) Nokogiri?
Designers
Friday, May 7, 2010
41. Anybody ever hit the “can’t activate gem foo,
already activated foo at another version error”?
No conflicts
Friday, May 7, 2010
51. In Rails 2.3, all view helpers that required JS would spew out a whole bunch
of Prototype specific javascript inline.
This is bad.
Helpers do not generate JS
anymore
Friday, May 7, 2010
52. Rails 3.0 helpers will now only output HTML. All required information
will be added to the HTML tags via data-*
Custom data-* attributes were added in HTML5, but they work in all
old and busted (IE 6).
<%= link_to "hello", hello_path, :remote => true %>
<a href="/hello" data-remote="true">hello</a>
Friday, May 7, 2010
53. public/javascripts/rails.js
$(document.body).observe("click", function(event) {
// ....
var element = event.findElement(
"a[data-remote]");
if (element) {
handleRemote(element);
event.stop();
return true;
}
The javascript that handles all the data-* attributes is in rails.js
// ....
});
Friday, May 7, 2010
54. Who uses jQuery?
Using jQuery?
http://github.com/rails/jquery-ujs
Rails will ship with the Prototype driver, but you can just drop in the
jquery driver at public/javascripts/rails.js
We maintain it and it’s on github at the URL.
You can finally easily completely rid your Rails app of all Prototype
Friday, May 7, 2010
55. public/javascripts/rails.js
$('a[data-remote],input[data-remote]').
live('click', function (e) {
$(this).callRemote();
e.preventDefault();
});
This is the code that is in the jQuery rails.js driver
Friday, May 7, 2010
56. Other wins too.
Pick your JS framework when you
write JS, not when you generate
your Rails app.
Friday, May 7, 2010
57. Just JS events being triggered. You can easily
replace specific default behavior.
There are events that are triggered that you can
bind to. ajax:before, ajax:after, etc...
Customizable
Friday, May 7, 2010
58. Rails is like a toolkit to build rails. Think
about it.
Everything is a “plugin”
Friday, May 7, 2010
68. Railtie is a class that integrates a library with
rails.
Look at how ActiveRecord does it. Look at how
everything else does it.
Railtie
When we built Rails 3, we didn’t add hook points for all
these other libraries after the fact. We made hooks for
ourselves to use, which has the nice side effect of other
libraries being able to use them.
RSpec, DataMapper, HAML, etc... all use the same hooks
that Rails uses
Friday, May 7, 2010
69. Configuration
Rake Tasks
Generator Overrides
You actually rarely need a Railtie to
integrate with Rails. Railties are for a
few specific things.
Initializers
Friday, May 7, 2010
70. Configuration
Rake Tasks
Generator Overrides
Provide configuration opportunities to Rails
applications
config.active_record in config/application.rb
Initializers
If you want to provide default config values, you need
a Railtie
Friday, May 7, 2010
71. Configuration
Rake Tasks
Generator Overrides
All ActiveRecord’s rake tasks are in
it’s Railtie, which means that when
AR isn’t required, the rake tasks go
away. Initializers
If you want to easily provide Rake
tasks to a Rails app, you need a Railtie
Friday, May 7, 2010
72. If you want to hook in to:
* rails generate controller Foo
* rails generate model Configuration
Foo
you need a Railtie. RSpec uses this to provide the same
level of integration thatRake Tasks
TestUnit gets
Generator Overrides
Initializers
Friday, May 7, 2010
73. If you want to hook into the initialization
Configuration
cycle of a Rails application, you’ll need a
Railtie
Rake Tasks
Generator Overrides
Initializers
Friday, May 7, 2010
75. Rails 2.3
<p>
<%= h @comment.title %>
(by <%= h @comment.author.username %>)
</p>
<%= simple_format h(@comment.body) %>
This is what a view might have looked in Rails 2.3
Friday, May 7, 2010
76. Rails 2.3
<p>
<%= h @comment.title %>
(by <%= h @comment.author.username %>)
</p>
<%= simple_format h(@comment.body) %>
If you forget one spot, you’re site gets hacked
... I’m sure everybody here has missed at least 1
spot to escape
Friday, May 7, 2010
77. Rails 3.0
New! No more pesky h()
<p>
<%= @comment.title %>
(by <%= @comment.author.username %>)
</p>
<%= simple_format(@comment.body) %>
Now, you don’t have to worry about
escaping anything anymore. Rails does it
for you.
Friday, May 7, 2010
79. app/helpers/application_helper.rb
def escaped(str) Simply returning a string a
str string will be escaped.
end
If you don’t want a string to be
def not_escaped(str) escaped, you just mark it as
str.html_safe html_safe and it won’t be
end modified by Rails.
Friday, May 7, 2010
81. Rails 2.3
This is what block
<% form_for @post do |f| %> helpers might look
<%= f.text_field :title %>
like in 2.3
<% end %>
<% box do %>
<p>Hello World!</p>
<% end %>
Friday, May 7, 2010
82. Rails 2.3
def box(&block)
This is the
content = "<div class='box'>" <<
capture(&block) << "</div>"
implementation.
if block_called_from_erb? I’m not even going to
concat(content) really talk about this,
else Just notice that it’s
content crazy
end
end Most of this is needed
to make the helper
work in and outside of
ERB.
Friday, May 7, 2010
83. Rails 2.3
Outputs method’s return value
<% form_for @post do |f| %>
<%= f.text_field :title %>
<% end %>
Ignores method’s return value
<% box do %>
<p>Hello World!</p> The reason why you
<% end %> need the craziness
is because of how
ERB works.
Friday, May 7, 2010
84. Rails 3.0
<%= form_for @post do |f| %> In Rails 3.0 block helpers
<%= f.text_field :title %>
have become consistent
<% end %>
with ERB.
form_for will actually
<%= box do %>
output content to the
<p>Hello World!</p>
view, aka, the form tags.
<% end %>
So, now you use %=
The same goes for
custom block helpers
Friday, May 7, 2010
85. Rails 3.0
def box(&block) All you do now for
"<div class='box'>"
block helpers is return
the string that you
"#{capture(&block)}"
want outputted to the
"</div>" view.
end
Block helpers aren’t
special anymore. They
work the same inside
and outside ERB
Friday, May 7, 2010
86. Rails 3.0
def box(&block)
"<div class='box'>"
"#{capture(&block)}"
"</div>".html_safe
end
Friday, May 7, 2010
88. You don’t have to rush to update your route file
to get on Rails 3.0
The old DSL will probably stop working in Rails
3.1 or 3.2, but you have time before that
happens.
Old DSL still works, just
deprecated.
Friday, May 7, 2010
90. Matching
map.connect "/posts", :controller => :posts,
:action => :index
match "/posts" => "posts#index"
posts#index is short hand for specifying the
controller and action. It’s just much easier to write.
Friday, May 7, 2010
91. Optional Segments
match "/posts(/:page)" => "posts#index"
Will match a request to /posts, and a request
to /posts/5
if page is not there, params[:page] will be nil, if
it is present in the request, the param will be set.
Friday, May 7, 2010
92. Defaults
You can specify default parameters. If the page
segment is not in the Request, params[:page] will
be set to 1
match "/posts(/:page)" => "posts#index",
:defaults => { :page => 1 }
Friday, May 7, 2010
93. Named Routes
The same helpers are available.
* posts_path
* posts_url
match "/posts(/:page)" => "posts#index",
:defaults => { :page => 1 }, :as => "posts"
Friday, May 7, 2010
94. Scopes
Let’s you set the same options to a group of routes.
Almost anything can be scoped.
Friday, May 7, 2010
95. Path Scopes
/admin/posts
scope :path => "/admin" do
match "/posts" => "posts#index"
match "/users" => "users#index"
end
Friday, May 7, 2010
96. Path Scopes
Paths are probably the most common
item to scope on, so it’s the default.
scope "/admin" do
match "/posts" => "posts#index"
match "/users" => "users#index"
end
Friday, May 7, 2010
97. Module Scope
Routes to Admin::PostsController /
Admin::UsersController
scope :module => "admin" do
match "/posts" => "posts#index"
match "/users" => "users#index"
end
Friday, May 7, 2010
98. Both
namespace "admin" do
match "/posts" => "posts#index"
match "/users" => "users#index"
end
Friday, May 7, 2010
99. HTTP Methods
Routing by specific HTTP
methods
Friday, May 7, 2010
100. POST Request
match "/posts" => "posts#index",
:via => "delete"
Any HTTP method can be
used here
Friday, May 7, 2010
101. Scoping
scope "/posts" do
controller :posts do
get "/" => :index
end
end
Friday, May 7, 2010
102. Scoping
scope "/posts" do Yet another
controller :posts do shorthand
get "/" => :index
end
end
Friday, May 7, 2010
103. Scoping
scope "/posts" do get URL
controller :posts do
get "/" => :index
end
end
Friday, May 7, 2010
104. Scoping
get / post / post / delete methods are shorthands for :via
=> “get”
This method can be used anywhere in the routes file
get "/posts" => "posts#index"
Friday, May 7, 2010
106. Regexp Constraint
get "/:id" => "posts#index", :id => /d+/
Friday, May 7, 2010
107. Regexp Constraint
Constraints on arbitrary methods of Request object.
Will use the “user_agent” method on the Request object
get "/posts" => "posts#mobile",
:user_agent => /iPhone/
Friday, May 7, 2010
109. Constraint + Default
How does it not get confused?
If you use a Regex on as the value of the hash, it is
a constraint, other wise, it is a default
get "/posts" => "posts#mobile",
:user_agent => /iPhone/, :mobile => true
Friday, May 7, 2010
110. Object Constraints
Any object that responds to matches? can be a router constraint
class DubDubConstraint
def self.matches?(request)
request.host =~ /^(www.)/ # true / false
end
end
get "/" => "posts#index",
:constraints => DubDubConstraint
Friday, May 7, 2010
111. Everything that used to be in ActionController that made sense without
ActionController. There is a lot, all rack middleware.
* Session
* Cookies
* Router
* Flash
* etc..
Rack Everywhere
Can be used without AC and only Rack. This is the
minimum requirement for “Rails”
Friday, May 7, 2010
112. Rack
You can get a rack app for any controller action
PostsController.action(:index)
Friday, May 7, 2010
113. Routing + Rack
This is what happens behind the scenes in my previous
examples
get "/posts" =>
PostsController.action(:index)
Friday, May 7, 2010
114. Routing + Rack
Just a Rack app
get "/posts" =>
PostsController.action(:index)
Friday, May 7, 2010
115. Routing + Rack
Any Rack app
get "/posts" =>
PostsController.action(:index)
Friday, May 7, 2010
116. Routing + Rack
Sinatra app
get "/posts" =>
MySinatraPostsApp
Friday, May 7, 2010
117. Routing + Rack
Camping app
get "/posts" =>
MyCampingPostsApp
Friday, May 7, 2010
118. Routing + Rack
Ramaze app
get "/posts" =>
MyRamazePostsApp
Friday, May 7, 2010
119. Routing + Rack
The possibilities
are endless
Any Rack app
get "/posts" =>
MyConstantThatRespondsToCall
Friday, May 7, 2010
121. It’s new
Massive API overhaul
I’m out of time
Friday, May 7, 2010
122. A lot of detailed stuff about what’s new with Rails 3.
* Articles
* Blog posts
* Screencasts
* QAs
* Aggregation of other Rails 3 info
Friday, May 7, 2010
124. Upgrading
I want to mention upgrading really quick
Rails 1.x apps -> 3.0 is really easy (15 minutes)
Rails 2.x is a little bit harder
Friday, May 7, 2010
125. Step 1) Generate a new app
Look at the generated
file structure
Friday, May 7, 2010
128. It will try to find all deprecated but still working methods as well
* Router
* AR API
* config/*
* Deprecated constants
http://github.com/rails/rails_upgrade
* Mail API
* Known broken plugins
* Helpers
* But all this stuff still will work in rails 3, just will
spew out deprecation notices.
Friday, May 7, 2010
129. Questions?
We have 2 other Rails core people here, they can answer
questions too.
Friday, May 7, 2010
130. Questions?
Email: me@carllerche.com (I accept fan mail)
Twitter: @carllerche (I’m interesting. Really!)
I will tweet the slides. So make sure
you are following me.
Friday, May 7, 2010