look / rails23-10coolfeatures
A simple application that demonstrates ten cool features in Rails 2.3, for my presentation at Ruby Users of Minnesota, March 30, 2009.
Clone this repository (size: 103.7 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/look/rails23-10coolfeatures/
| commit 16: | fcdb26796c04 |
| parent 15: | 40415381e533 |
Update README with link to blog post. Synergy!
| filename | size | last modified | ||
|---|---|---|---|---|
| app | ||||
| config | ||||
| db | ||||
| doc | ||||
| examples | ||||
| public | ||||
| script | ||||
| test | ||||
| .hgignore | 35 B | 11 months ago | fix .hgignore for log files | |
| README | 8.1 KB | 11 months ago | Update README with link to blog post. Synergy! | |
| Rakefile | 307 B | 11 months ago | initial, empty rails app |
README
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | 10 Cool Features in Rails 2.3
A contrived example application by Luke Francl, for a presentation to
the Ruby Users of Minnesota on March 30, 2009.
Website: http://railspikes.com/2009/3/30/10-cool-things-in-rails-23
Slides: http://www.slideshare.net/lukefrancl/10-cool-things-about-rails-23
1. Rails Boots Faster in Development Mode
This is something all Rails developers can appreciate. In development
mode, Rails now lazy loads as much as possible so that the server
starts up much faster.
This is so fast, instead of replying on reloading (which doesn't pick
up changes to gems, lib directory, etc) one developer wrote a script
that watches for file system changes and restarts your script/server
process.
Using an empty Rails app, I got the following (totally non-scientific)
real times for time script/server -d:
Rails 2.2: 1.461s
Rails 2.3: 0.869s
Presumably this difference would grow as more libraries were used,
because Rails 2.3 will lazy load them.
2. Rails Engines Officially Supported
Inspired by Merb's slices implementation, Rails added official support
for Engines, which are self-contained Rails apps that you can install
into another application. Engines can have their own models,
controllers, and views, and add their own routes.
Previously this was possible using the Engines plugin, but Engines
would often break between Rails versions. Now that they are officially
supported, this should be less frequent.
There are still some features from the unofficial Engines plugin that
are not part of Rails core. You can read about that here:
http://rails-engines.org/news/2009/02/02/engines-in-rails-2-3/
3. Routing Improvements
RESTful routes now use less memory because formatted_* routes are no
longer generated, resulting in a 50% memory savings.
Given this route:
map.resources :users
If you want to access the XML formatted version of a user resource, you would use:
user_path(123, :format => 'xml')
In Rails 2.3, :only and :except options to map.resources are not
passed down to nested routes. The previous behavior was rather
confusing so I think this is a good change.
map.resources :users, :only => [:index, :new, :create] do |user|
# now will generate all the routes for hobbies
user.resources :hobbies
end
See: config/routes.rb
4. JSON Improvements
ActiveSupport::JSON has been improved.
to_json will always quote keys now, per the JSON spec.
Before:
{123 => 'abc'}.to_json
=> '{123: "abc"}'
Now:
{123 => 'abc'}.to_json
=> '{"123": "abc"}'
Escaped Unicode characters will now be unescaped.
Before:
ActiveSupport::JSON.decode("{'hello': 'fa\\u00e7ade'}")
=> {"hello"=>"fa\\u00e7ade"}
Now:
ActiveSupport::JSON.decode("{'hello': 'fa\u00e7ade'}")
=> {"hello"=>"façade"}
See: https://rails.lighthouseapp.com/projects/8994/tickets/1100
5. Default scopes
Prior to Rails 2.3, if you executed a find without any options, you'd
get the objects back unordered (technically, the database does
not *guarantee* a particular ordering, but it would typically be by
primary key, ascending).
Now, you can define the default sort and filtering options for finding
models. The default scope works just like a named scope, but is used
by default.
# in user.rb
default_scope :order => 'name asc'
The default options can always be overridden using a custom finder.
User.all # will use default scope
User.all(:order => 'name desc') # will use passed in order option.
Example:
User.create(:name => 'George')
User.create(:name => 'Bob')
User.create(:name => 'Alice')
puts User.all.map { |u| "#{u.id} - #{u.name}" }
3 - Alice
2 - Bob
1 - George
Note how the default order is respected.
See: app/models/user.rb
6. Nested Transactions
User.transaction do
user1 = User.create(:name => "Alice")
User.transaction(:requires_new => true) do
user2 = User.create(:name => "Bob")
end
end
This is actually emulated using save points because most databases do
not support nested transactions. Some databases (SQLite) don't support
either save points or nested transactions, so in that case this works
just like Rails 2.2 where the inner transaction(s) have no effect and
if there are any exceptions the entire transaction is rolled back.
See: examples/nested_transactions.rb
7. Asset Host Objects
Since Rails 2.1, you could configure Rails to use an asset_host that
was a Proc with two arguments, source and request.
For example, some browsers complain if an SSL request loads images
from a non-secure source. To make sure SSL always loads from the same
host, you could write this (from the documentation):
ActionController::Base.asset_host = Proc.new { |source, request|
if request.ssl?
"#{request.protocol}#{request.host_with_port}"
else
"#{request.protocol}assets.example.com"
end
}
This works but it's kind of messy and it's difficult to implement
complicated logic. Rails 2.3 allows you to implement the logic in an
object that responds to call with one or two parameters, like the
Proc.
The above Proc could be implemented like this:
class SslAssetHost
def call(source, request)
if request.ssl?
"#{request.protocol}#{request.host_with_port}"
else
"#{request.protocol}assets.example.com"
end
end
end
ActionController::Base.asset_host = SslAssetHost.new
David Heinemeier Hansson has already created a better plugin that
handles this case: asset-hosting-with-minimum-ssl. It takes into
account the peculiarities of the different browsers to use SSL as
little as possible.
See: http://github.com/dhh/asset-hosting-with-minimum-ssl/tree/master
See: http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html
8. Easily update Rails timestamp fields
If you've ever wanted to update Rails' automatic timestamp fields
created_at or updated_at you've noticed how painful it can be. Rails
REALLY didn't want you to change those fields.
Not any more!
Now you can easily change created_at and updated_at:
User.create(:name => "Alice",
:created_at => 3.weeks.ago,
:updated_at => 2.weeks.ago)
=> #<User id: 3, name: "Alice", created_at: "2009-03-08 00:06:58", updated_at: "2009-03-15 00:06:58">
9. Nested Attributes and Forms
This greatly simplifies complex forms that deal with multiple objects.
First, nested attributes allow a parent object to delegate assignment to its child objects.
class User < ActiveRecord::Base
has_many :hobbies, :dependent => :destroy
accepts_nested_attributes_for :hobbies
end
User.create(:name => 'Stan', :hobbies_attributes => [{:name => 'Water skiing'},
{:name => 'Hiking'}])
Nicely, this will save the parent and its associated models together
and if there are any errors, none of the objects will be saved.
Forms with complex objects are now straight-forward. To use this in
your forms, use the FormBuilder instance's fields_for method.
<% form_for(@user) do |f| %>
...
<% f.fields_for(:hobbies) do |hf| %>
...
<% end %>
<% end %>
One catch is that a form is displayed for every associated object. New
objects obviously have no associations so you have to create a dummy
object in your controller.
There are a lot of options for nested forms including deleting associated objects, so be sure to read the documentation.
See:
http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes
See: app/models/user.rb, app/controllers/users_controller.rb,
app/views/users/new.html.erb
10. Rails Metal \m/
You can now write very simple Rack endpoints for highly trafficked
routes, like an API. These are slotted in before Rails picks up the
route.
A Metal endpoint is any class that conforms to the Rack spec (i.e., it
has a call method that takes an environment and returns the an array
of status code, headers, and content).
Put your class in app/metal (not generated by default). Return a 404
response code for any requests you don't want to handle.
There's a generator you can use to create an example Metal end point:
script/generate metal classname
If you want a little bit more help, you can use any other Rack-based
framework, for example Sinatra.
See:
http://soylentfoo.jnewland.com/articles/2008/12/16/rails-metal-a-micro-framework-with-the-power-of-rails-m
See: app/metal/users_api.rb
|
