David Heinemeier Hansson
2006-Mar-28 06:33 UTC
[ANN] RJS, Active Record++, respond_to, integration tests, and 500 other things!
The biggest upgrade in Rails history has finally arrived. Rails 1.1 boasts more than 500 fixes, tweaks, and features from more than 100 contributors. Most of the updates just make everyday life a little smoother, a little rounder, and a little more joyful. But of course we also have an impressive line of blockbuster features that will make you an even happier programmer. Especially if you''re into Ajax, web services, and strong domain models — and who isn''t these funky days? *RJS: Ajax has never been easier* The star of our one-one show is RJS: JavaScript written in Ruby. It''s the perfect antidote for your JavaScript blues. The way to get all Ajaxified without leaving the comfort of your beloved Ruby. It''s the brainchild of JavaScript and Ruby mastermind Sam Stephenson and an ode to the dynamic nature of Ruby. Here goes a few sample rjs calls: # First buy appears the cart, subsequent buys highlight it page[:cart].visual_effect(@cart.size == 1 ? :appear : :highlight) # Replace the cart with a refresh rendering of the cart partial page[:cart].replace_html :partial => "cart" # Highlight all the DOM elements of class "product" page.select(".product").each do |element| element.visual_effect :highlight end # Call the custom JavaScript class/method AddressBook.cancel() page.address_book.cancel # 4 seconds after rendering, set the font-style of all company # spans inside tds to normal page.delay(4) do page.select("td span.company").each do |column| column.set_style :fontStyle => "normal" end end And that''s just a tiny taste of what RJS is capable of. It takes the Ajax on Rails experience far above and beyond the great support we already had. Bringing us even closer to the goal of "as easy as not to". *Active Record''s major upgrade* But its not just the view we''re giving some tender love, oh no. Active Record has been blessed with bottomless eager loading, polymorphic associations, join models, to_xml, calculations, and database adapters for Sybase and OpenBase. It''s a huge upgrade and made possible through the fantastic work of Rick Olson (who was recently accepted into Rails Core, not a minute too soon!) and Anna Chan. Let''s dig into three of the top features: Bottomless eager loading gives you the power of pulling back a multi-level object graph in a single JOIN-powered SQL query. Example: # Single database query: companies = Company.find(:all, :include => { :groups => { :members=> { :favorites } } }) # No database query caused: companies[0].groups[0].members[0].favorites[0].name You can mix''n''match too. Using both multi-level fetches and first-level ones in the same call: # Just 1 database query for all of this: authors = Author.find(:all, :include => [ { :posts => :comments }, :categorizations ]) authors[0].posts[0].comments[0].body # => "Rock on Rails!" authors[0].categorizations[0].name # => "Less software" Polymorphic associations and join models give you access to much richer domains where many-to-many relationships are exposed as real models. Say Authorship between Book and Author: <pre> class Author < ActiveRecord::Base has_many :authorships has_many :books, :through => :authorships end class Book < ActiveRecord::Base has_many :authorships has_many :authors, :through => :authorships end class Authorship < ActiveRecord::Base belongs_to :author belongs_to :book end </pre> ...or addresses that can belong to both people and companies: <pre> class Address < ActiveRecord::Base belongs_to :addressable, :polymorphic => true end class Person < ActiveRecord::Base has_one :address, :as => :addressable end class Company < ActiveRecord::Base has_one :address, :as => :addressable end </pre> *Add an API with minimal effort* Now let''s have a look at the new respond_to feature of Action Controller that makes it much easier to launch your application with both Ajax, non-Ajax, and API access through the same actions. By inspecting the Accept header, we can do clever stuff like: class WeblogController < ActionController::Base def create @post = Post.create(params[:post]) respond_to do |type| type.js { render } # renders create.rjs type.html { redirect_to :action => "index" } type.xml do headers["Location"] = post_url(:id => @post) render(:nothing, :status => "201 Created") end end end end The recently launched API for Basecamp uses this approach to stay DRY and keep Jamis happy. So happy that he wrote a great guide on how to use respond_to: http://jamis.jamisbuck.org/articles/2006/03/27/web-services-rails-style *The third testing layer: Integration* Speaking of Jamis, he also added the third layer of testing to Rails: Integration tests. They allow you to faithfully simulate users accessing multiple controllers and even gives you the power to simulate multiple concurrent users. It can really give you a whole new level of confidence in your application. The 37signals team used it heavily in Campfire from where it was later extracted into Rails. See Jamis'' "great guide to integration testing: http://jamis.jamisbuck.org/articles/2006/03/09/integration-testing-in-rails-1-1 *What else is new?* These highlighted features are just the tip of the iceberg. Scott Raymond has done a great job trying to keep a tab on all the changes, see his What new in Rails 1.1 (http://scottraymond.net/articles/2006/02/28/rails-1.1) for a more complete, if brief, walk-through of all the goodies. And as always, the changelogs has the complete step-by-step story for those of you who desire to know it all. *Upgrading from 1.0* So with such a massive update, upgrading is going to be hell, right? Wrong! We''ve gone to painstaking lengths to ensure that upgrading from 1.0 will be as easy as pie. Here goes the steps: * Update to Rails 1.1: gem install rails --include-dependencies * Update JavaScripts for RJS: rake rails:update That''s pretty much it! If you''re seeing any nastiness after upgrading, it''s most likely due to a plugin that''s incompatible with 1.1. See if the author hasn''t updated it and otherwise force him to do so. If you''re on Ruby 1.8.2 with Windows, though, you''ll want to upgrade to the 1.8.4 (or the script/console will fail). And even if you''re on another platform, it''s a good idea to upgrade to Ruby 1.8.4. We still support 1.8.2, but might not in the next major release. So may as well get the upgrading with over with now. -- David Heinemeier Hansson http://www.loudthinking.com -- Broadcasting Brain http://www.basecamphq.com -- Online project management http://www.backpackit.com -- Personal information manager http://www.rubyonrails.com -- Web-application framework
Nathaniel Brown
2006-Mar-28 08:25 UTC
[Rails] FW: [ANN] RJS, Active Record++, respond_to, integration tests, and 500 other things!
------ Forwarded Message From: David Heinemeier Hansson <david.heinemeier@gmail.com> Date: Tue, 28 Mar 2006 15:34:11 +0900 Subject: [ANN] RJS, Active Record++, respond_to, integration tests, and 500 other things! The biggest upgrade in Rails history has finally arrived. Rails 1.1 boasts more than 500 fixes, tweaks, and features from more than 100 contributors. Most of the updates just make everyday life a little smoother, a little rounder, and a little more joyful. But of course we also have an impressive line of blockbuster features that will make you an even happier programmer. Especially if you''re into Ajax, web services, and strong domain models — and who isn''t these funky days? *RJS: Ajax has never been easier* The star of our one-one show is RJS: JavaScript written in Ruby. It''s the perfect antidote for your JavaScript blues. The way to get all Ajaxified without leaving the comfort of your beloved Ruby. It''s the brainchild of JavaScript and Ruby mastermind Sam Stephenson and an ode to the dynamic nature of Ruby. Here goes a few sample rjs calls: # First buy appears the cart, subsequent buys highlight it page[:cart].visual_effect(@cart.size == 1 ? :appear : :highlight) # Replace the cart with a refresh rendering of the cart partial page[:cart].replace_html :partial => "cart" # Highlight all the DOM elements of class "product" page.select(".product").each do |element| element.visual_effect :highlight end # Call the custom JavaScript class/method AddressBook.cancel() page.address_book.cancel # 4 seconds after rendering, set the font-style of all company # spans inside tds to normal page.delay(4) do page.select("td span.company").each do |column| column.set_style :fontStyle => "normal" end end And that''s just a tiny taste of what RJS is capable of. It takes the Ajax on Rails experience far above and beyond the great support we already had. Bringing us even closer to the goal of "as easy as not to". *Active Record''s major upgrade* But its not just the view we''re giving some tender love, oh no. Active Record has been blessed with bottomless eager loading, polymorphic associations, join models, to_xml, calculations, and database adapters for Sybase and OpenBase. It''s a huge upgrade and made possible through the fantastic work of Rick Olson (who was recently accepted into Rails Core, not a minute too soon!) and Anna Chan. Let''s dig into three of the top features: Bottomless eager loading gives you the power of pulling back a multi-level object graph in a single JOIN-powered SQL query. Example: # Single database query: companies = Company.find(:all, :include => { :groups => { :members=> { :favorites } } }) # No database query caused: companies[0].groups[0].members[0].favorites[0].name You can mix''n''match too. Using both multi-level fetches and first-level ones in the same call: # Just 1 database query for all of this: authors = Author.find(:all, :include => [ { :posts => :comments }, :categorizations ]) authors[0].posts[0].comments[0].body # => "Rock on Rails!" authors[0].categorizations[0].name # => "Less software" Polymorphic associations and join models give you access to much richer domains where many-to-many relationships are exposed as real models. Say Authorship between Book and Author: <pre> class Author < ActiveRecord::Base has_many :authorships has_many :books, :through => :authorships end class Book < ActiveRecord::Base has_many :authorships has_many :authors, :through => :authorships end class Authorship < ActiveRecord::Base belongs_to :author belongs_to :book end </pre> ...or addresses that can belong to both people and companies: <pre> class Address < ActiveRecord::Base belongs_to :addressable, :polymorphic => true end class Person < ActiveRecord::Base has_one :address, :as => :addressable end class Company < ActiveRecord::Base has_one :address, :as => :addressable end </pre> *Add an API with minimal effort* Now let''s have a look at the new respond_to feature of Action Controller that makes it much easier to launch your application with both Ajax, non-Ajax, and API access through the same actions. By inspecting the Accept header, we can do clever stuff like: class WeblogController < ActionController::Base def create @post = Post.create(params[:post]) respond_to do |type| type.js { render } # renders create.rjs type.html { redirect_to :action => "index" } type.xml do headers["Location"] = post_url(:id => @post) render(:nothing, :status => "201 Created") end end end end The recently launched API for Basecamp uses this approach to stay DRY and keep Jamis happy. So happy that he wrote a great guide on how to use respond_to: http://jamis.jamisbuck.org/articles/2006/03/27/web-services-rails-style *The third testing layer: Integration* Speaking of Jamis, he also added the third layer of testing to Rails: Integration tests. They allow you to faithfully simulate users accessing multiple controllers and even gives you the power to simulate multiple concurrent users. It can really give you a whole new level of confidence in your application. The 37signals team used it heavily in Campfire from where it was later extracted into Rails. See Jamis'' "great guide to integration testing: http://jamis.jamisbuck.org/articles/2006/03/09/integration-testing-in-rails- 1-1 *What else is new?* These highlighted features are just the tip of the iceberg. Scott Raymond has done a great job trying to keep a tab on all the changes, see his What new in Rails 1.1 (http://scottraymond.net/articles/2006/02/28/rails-1.1) for a more complete, if brief, walk-through of all the goodies. And as always, the changelogs has the complete step-by-step story for those of you who desire to know it all. *Upgrading from 1.0* So with such a massive update, upgrading is going to be hell, right? Wrong! We''ve gone to painstaking lengths to ensure that upgrading from 1.0 will be as easy as pie. Here goes the steps: * Update to Rails 1.1: gem install rails --include-dependencies * Update JavaScripts for RJS: rake rails:update That''s pretty much it! If you''re seeing any nastiness after upgrading, it''s most likely due to a plugin that''s incompatible with 1.1. See if the author hasn''t updated it and otherwise force him to do so. If you''re on Ruby 1.8.2 with Windows, though, you''ll want to upgrade to the 1.8.4 (or the script/console will fail). And even if you''re on another platform, it''s a good idea to upgrade to Ruby 1.8.4. We still support 1.8.2, but might not in the next major release. So may as well get the upgrading with over with now. -- David Heinemeier Hansson http://www.loudthinking.com -- Broadcasting Brain http://www.basecamphq.com -- Online project management http://www.backpackit.com -- Personal information manager http://www.rubyonrails.com -- Web-application framework ------ End of Forwarded Message