aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
Diffstat (limited to 'railties')
-rw-r--r--railties/guides/source/3_0_release_notes.textile550
-rw-r--r--railties/guides/source/action_controller_overview.textile4
-rw-r--r--railties/guides/source/active_support_core_extensions.textile140
-rw-r--r--railties/guides/source/contributing_to_rails.textile21
-rw-r--r--railties/guides/source/credits.textile.erb8
-rw-r--r--railties/guides/source/getting_started.textile495
-rw-r--r--railties/guides/source/layouts_and_rendering.textile370
-rw-r--r--railties/guides/source/routing.textile208
-rw-r--r--railties/lib/rails/railtie.rb108
-rw-r--r--railties/lib/rails/subscriber.rb15
10 files changed, 1381 insertions, 538 deletions
diff --git a/railties/guides/source/3_0_release_notes.textile b/railties/guides/source/3_0_release_notes.textile
new file mode 100644
index 0000000000..690bda0427
--- /dev/null
+++ b/railties/guides/source/3_0_release_notes.textile
@@ -0,0 +1,550 @@
+h2. Ruby on Rails 3.0 Release Notes
+
+Rails 3.0 is a landmark release as it delivers on the Merb/Rails merge promise made in December 2008. Rails 3.0 provides major upgrades to all of the components of Rails, including a complete overhaul of the router and query APIs.
+
+One of the main achievements of this release, is that while there are loads of new features, old APIs have been deprecated with warnings wherever possible, so that you can implement the new features and conventions at your own pace. There is a backwards compatibility layer that will be supported during 3.0.x and removed in 3.1.
+
+Rails 3.0 adds Active Model ORM abstraction, Abstract Controller generic controller abstraction as well as a consistent Plugin API giving developers full access to all the Rails internals that make Action Mailer, Action Controller, Action View, Active Record and Active Resource work.
+
+These release notes cover the major upgrades, but don't include every little bug fix and change. If you want to see everything, check out the "list of commits":http://github.com/rails/rails/commits/master in the main Rails repository on GitHub.
+
+endprologue.
+
+
+h3. Upgrading from Rails 2.3.5 to Rails 3.0
+
+As always, having a high coverage, passing test suite is your friend when upgrading. You should also first upgrade to Rails 2.3.5 and make sure your application still runs as expected before attempting to update to Rails 3.0. In general, the upgrade from Rails 2.x to 3.0 centers around three big changes:
+
+
+h4. New Ruby Version Requirement
+
+WARNING: Rails only runs on version 1.8.7 of Ruby or later. Support for previous versions of Ruby has been dropped and Rails 3.0 will no longer boot on any of these versions.
+
+
+h4. The new boot process
+
+As part of the shift to treating Rails apps as Rack endpoints, you are now required to have a +config/application.rb+ file, which takes over much of the work +config/environment.rb+ used to handle. Along with that comes a lot of internal change to the boot process, but those changes are mostly internal.
+
+
+h4. Gems and gems and gems
+
+The +config.gem+ method is gone and has been replaced by using +bundler+ and a +Gemfile+, see "Vendoring Gems":#vendoring-gems below.
+
+
+h4. New APIs
+
+Both the router and query interface have seen significant, breaking changes. There is a backwards compatibility layer that is in place and will be supported until the 3.1 release.
+
+
+h4. Upgrade Process
+
+To help with the upgrade process, a plugin named "Rails Upgrade":http://github.com/rails/rails_upgrade has been created to automate part of it.
+
+Simply install the plugin, then run +rake rails:upgrade:check+ to check your app for pieces that need to be updated (with links to information on how to update them). It also offers a task to generate a +Gemfile+ based on your current +config.gem+ calls and a task to generate a new routes file from your current one. To get the plugin, simply run the following:
+
+<shell>
+script/plugin install git://github.com/rails/rails_upgrade.git
+</shell>
+
+You can see an example of how that works at "Rails Upgrade is now an Official Plugin":http://omgbloglol.com/post/364624593/rails-upgrade-is-now-an-official-plugin
+
+Aside from Rails Upgrade tool, if you need more help, there are people on IRC and "rubyonrails-talk":http://groups.google.com/group/rubyonrails-talk that are probably doing the same thing, possibly hitting the same issues. Be sure to blog your own experiences when upgrading so others can benefit from your knowledge!
+
+More information - "The Path to Rails 3: Approaching the upgrade":http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade
+
+
+h3. Application Creation
+
+As stated above, you must be on Ruby 1.8.7 or later to boot up a Rails application. Rails will no longer boot on Ruby 1.8.6 or earlier.
+
+Rails 3.0 is designed to run on 1.8.7 and also support Ruby 1.9.
+
+There have been a few changes to the +rails+ script that's used to generate Rails applications:
+
+* The application name, <tt>rails my_app</tt>, can now optionally be a path instead <tt>rails ~/code/my_app</tt>, your rails application will be name spaced under the application name you pass the +rails+ command.
+* Additionally, any flags you need to generate the application now need to come after the application path, for example:
+
+<shell>
+$ rails myapp --database=mysql
+</shell>
+
+
+h4. Vendoring Gems
+
+Rails now uses a +Gemfile+ in the application root to determine the gems you require for your application to start. This +Gemfile+ is then read and acted on by the new "Bundler":http://github.com/wycats/bundler gem, which then vendors all your gems into the vendor directory, making your Rails application isolated from system gems.
+
+More information: - "Using bundler":http://yehudakatz.com/2009/11/03/using-the-new-gem-bundler-today/
+
+
+h4. Living on the Edge
+
+Due to the use of +Gemfile+, the concept of freezing Rails was dropped, because it's always bundled/frozen inside your application. By default, it uses your system gems when bundling; however, if you want to bundle straight from the Git repository, you can pass the edge flag:
+
+<shell>
+$ rails myapp --edge
+</shell>
+
+More information:
+* "Spinning up a new Rails app":http://yehudakatz.com/2009/12/31/spinning-up-a-new-rails-app/
+* "Rails 3 and Passenger":http://cakebaker.42dh.com/2010/01/17/rails-3-and-passenger/
+
+
+h3. Rails Architectural Changes
+
+There are six major changes in the architecture of Rails.
+
+
+h4. Railties Restrung
+
+Railties was updated to provide a consistent plugin API for the entire Rails framework as well as a total rewrite of generators and the Rails bindings, the result is that developers can now hook into any significant stage of the generators and application framework in a consistent, defined manner.
+
+
+h4. All Rails core components are decoupled
+
+With the merge of Merb and Rails, one of the big jobs was to remove the tight coupling between Rails core components. This has now been achieved, and all Rails core components are now using the same API that you can use for developing plugins. This means any plugin you make, or any core component replacement (like DataMapper or Sequel) can access all the functionality that the Rails core components have access to and extend and enhance at will.
+
+More information: - "The Great Decoupling":http://yehudakatz.com/2009/07/19/rails-3-the-great-decoupling/
+
+
+h4. Active Model Abstraction
+
+Part of decoupling the core components was extracting all ties to Active Record from Action Pack. This has now been completed. All new ORM plugins now just need to implement Active Model interfaces to work seamlessly with Action Pack.
+
+More information: - "Make Any Ruby Object Feel Like ActiveRecord":http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/
+
+
+h4. Controller Abstraction
+
+Another big part of decoupling the core components was creating a base superclass that is separated from the notions of HTTP in order to handle rendering of views etc. This creation of +AbstractController+ allowed +ActionController+ and +ActionMailer+ to be greatly simplified with common code removed from all these libraries and put into Abstract Controller.
+
+More Information: - "Rails Edge Architecture":http://yehudakatz.com/2009/06/11/rails-edge-architecture/
+
+
+h4. Arel Integration
+
+"Arel":http://github.com/brynary/arel (or Active Relation) has been taken on as the underpinnings of Active Record and is now required for Rails (it is installed for you when you do a <tt>gem bundle</tt>). Arel provides an SQL abstraction that simplifies out Active Record and provides the underpinnings for the relation functionality in Active Record.
+
+More information: - "Why I wrote Arel":http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/.
+
+
+h4. Mail Extraction
+
+Action Mailer ever since its beginnings has had monkey patches, pre parsers and even delivery and receiver agents, all in addition to having TMail vendored in the source tree. Version 3 changes that with all email message related functionality abstracted out to the "Mail":http://github.com/mikel/mail gem. This again reduces code duplication and helps create definable boundaries between Action Mailer and the email parser.
+
+More information: - "New Action Mailer API in Rails 3":http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3
+
+
+h3. Documentation
+
+The documentation in the Rails tree is being updated with all the API changes, additionally, the "Rails Edge guides":http://guides.rails.info/ are being updated one by one to reflect the changes in Rails 3.0. The guides at "guides.rubyonrails.org":http://guides.rubyonrails.org/ however will continue to contain only the stable version of Rails (at this point, version 2.3.5, until 3.0 is released).
+
+More Information: - "Rails Documentation Projects":http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects.
+
+
+h3. Internationalization
+
+Rails has many improvements in I18n support, including the latest "I18n":http://github.com/svenfuchs/i18n gem supplying many speed improvements.
+
+* I18n for any object - I18n behavior can be added to any object by including <tt>ActiveModel::Translation</tt> and <tt>ActiveModel::Validations</tt>. There is also an <tt>errors.messages</tt> fallback for translations.
+* Attributes can have default translations.
+* Form Submit Tags automatically pull the correct status (Create or Update) depending on the object status, and so pull the correct translation.
+* Labels with I18n also now work by just passing the attribute name.
+
+More Information: - "Speedup for I18n":http://blog.plataformatec.com.br/2009/12/run-i18n-run/
+
+
+h3. Railties
+
+With the decoupling of the main Rails frameworks, Railties got a huge overhaul so as to make linking up frameworks, engines or plugins as painless and extensible as possible:
+
+* Each application now has it's own name space, application is started with <tt>YourAppName.boot</tt> for example, makes interacting with other applications a lot easier.
+* You now have access to <tt>Rails.config</tt> which provides huge amount of configuration settings for your application.
+* Anything under <tt>Rails.root/app</tt> is now added to the load path, so you can make <tt>app/observers/user_observer.rb</tt> and Rails will load it without any modifications.
+* Rails 3.0 now provides a <tt>Rails.config</tt> object, which provides a central repository of all sorts of Rails wide configuration options.
+
+Application generation has received extra flags allowing you to skip the installation of test-unit, Active Record, Prototype and Git. Also a new <tt>--dev</tt> flag has been added which sets the application up with the +Gemfile+ pointing to your Rails checkout (which is determined by the path to the +rails+ binary). See <tt>rails --help</tt> for more info.
+
+Railties generators got a huge amount of attention in Rails 3.0, basically:
+
+* Generators were completely rewritten and are backwards incompatible.
+* Rails templates API and generators API were merged (they are the same as the former).
+* Generators are no longer loaded from special paths anymore, they are just found in the Ruby load path, so calling <tt>script/generate foo</tt> will look for <tt>generators/foo_generator</tt>.
+* New generators provide hooks, so any template engine, ORM, test framework can easily hook in.
+* New generators allow you to override the templates by placing a copy at <tt>RAILS_ROOT/lib/templates</tt>.
+* <tt>Rails::Generators::TestCase</tt> is also supplied so you can create your own generators and test them.
+
+Also, the views generated by Railties generators had some overhaul:
+
+* Views now use +div+ tags instead of +p+ tags.
+* Scaffolds generated now make use of <tt>_form</tt> partials, instead of duplicated code in the edit and new views.
+* Scaffold forms now use <tt>f.submit</tt> which returns "Create ModelName" or "Update ModelName" depending on the state of the object passed in.
+
+Finally a couple of enhancements were added to the rake tasks:
+
+* <tt>rake db:forward</tt> was added, allowing you to roll forward your migrations individually or in groups.
+* <tt>rake routes CONTROLLER=x</tt> was added allowing you to just view the routes for one controller.
+
+Railties now deprecates:
+
+* <tt>RAILS_ROOT</tt> in favour of <tt>Rails.root</tt>,
+* <tt>RAILS_ENV</tt> in favour of <tt>Rails.env</tt>, and
+* <tt>RAILS_DEFAULT_LOGGER</tt> in favour of <tt>Rails.logger</tt>.
+
+<tt>PLUGIN/rails/tasks</tt>, and <tt>PLUGIN/tasks</tt> are no longer loaded all tasks now must be in <tt>PLUGIN/lib/tasks</tt>.
+
+More information:
+* "Discovering Rails 3 generators":http://blog.plataformatec.com.br/2010/01/discovering-rails-3-generators
+* "Making Generators for Rails 3 with Thor":http://caffeinedd.com/guides/331-making-generators-for-rails-3-with-thor
+
+
+h3. Action Pack
+
+There have been significant internal and external changes in Action Pack.
+
+
+h4. Abstract Controller
+
+Abstract Controller pulls out the generic parts of Action Controller into a reusable module that any library can use to render templates, render partials, helpers, translations, logging, any part of the request response cycle. This abstraction allowed <tt>ActionMailer::Base</tt> to now just inherit from +AbstractController+ and just wrap the Rails DSL onto the Mail gem.
+
+It also provided an opportunity to clean up Action Controller, abstracting out what could to simplify the code.
+
+Note however that Abstract Controller is not a user facing API, you will not run into it in your day to day use of Rails.
+
+More Information: - "Rails Edge Architecture":http://yehudakatz.com/2009/06/11/rails-edge-architecture/
+
+
+h4. Action Controller
+
+* <tt>application_controller.rb</tt> now has <tt>protect_from_forgery</tt> on by default.
+* The <tt>cookie_verifier_secret</tt> has been moved to <tt>initializers/cookie_verification_secret.rb</tt>.
+* The <tt>session_store</tt> configuration has moved to <tt>initializers/session_store.rb</tt>.
+* <tt>cookies.secure</tt> allowing you to set encrypted values in cookies with <tt>cookie.secure[:key] => value</tt>.
+* <tt>cookies.permanent</tt> allowing you to set permanent values in the cookie hash <tt>cookie.permanent[:key] => value</tt> that raise exceptions on signed values if verification failures.
+* You can now pass <tt>:notice => 'This is a flash message'</tt> or <tt>:alert => 'Something went wrong'</tt> to the <tt>format</tt> call inside a +respond_to+ block. The <tt>flash[]</tt> hash still works as previously.
+* <tt>respond_with</tt> method has now been added to your controllers simplifying the venerable +format+ blocks.
+* <tt>ActionController::Responder</tt> added allowing you flexibility in how your responses get generated.
+
+Deprecations:
+
+* <tt>filter_parameter_logging</tt> is deprecated in favour of <tt>config.filter_parameters << :password</tt>.
+
+More Information:
+* "Render Options in Rails 3":http://www.engineyard.com/blog/2010/render-options-in-rails-3/
+* "Three reasons to love ActionController::Responder":http://weblog.rubyonrails.org/2009/8/31/three-reasons-love-responder
+
+
+h4. Action Dispatch
+
+Action Dispatch is new in Rails 3.0 and provides a new, cleaner implementation for routing.
+
+* Big clean up and re-write of the router, the Rails router is now +rack_mount+ with a Rails DSL on top, it is a stand alone piece of software.
+* Routes defined by each application are now name spaced within your Application module, that is:
+
+<ruby>
+# Instead of:
+
+ActionController::Routing::Routes.draw do
+ map.resources :posts
+end
+
+# You do:
+
+AppName::Application.routes do
+ resources :posts
+end
+</ruby>
+
+* Added +match+ method to the router, you can also pass any Rack application to the matched route.
+* Added +constraints+ method to the router, allowing you to guard routers with defined constraints.
+* Added +scope+ method to the router, allowing you to namespace routes for different languages or different actions, for example:
+
+<ruby>
+scope 'es' { resources :projects,
+ :path_names => { :edit => 'cambiar' },
+ :as => 'projeto' }
+
+# Gives you the edit action with /es/projeto/1/cambiar
+</ruby>
+
+* Added +root+ method to the router as a short cut for <tt>match '/', :to => path</tt>.
+* You can pass optional segments into the match, for example <tt>match "/:controller(/:action(/:id))(.:format)"</tt>, each parenthesized segment is optional.
+* Routes can be expressed via blocks, for example you can call <tt>controller :home { match '/:action' }</tt>.
+
+NOTE. The old style <tt>map</tt> commands still work as before with a backwards compatibility layer, however this will be removed in the 3.1 release.
+
+Deprecations
+
+* The catch all route for non-REST applications (<tt>/:controller/:action/:id</tt>) is now commented out.
+* Routes :path_prefix no longer exists and :name_prefix now automatically adds "_" at the end of the given value.
+
+More Information:
+* "The Rails 3 Router: Rack it Up":http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/
+* "Revamped Routes in Rails 3":http://rizwanreza.com/2009/12/20/revamped-routes-in-rails-3
+* "Generic Actions in Rails 3":http://yehudakatz.com/2009/12/20/generic-actions-in-rails-3/
+
+
+h4. Action View
+
+Major re-write was done in the Action View helpers, implementing Unobtrusive JavaScript (UJS) hooks and removing the old inline AJAX commands. This enables Rails to use any compliant UJS driver to implement the UJS hooks in the helpers.
+
+What this means is that all previous <tt>remote_<method></tt> helpers have been removed from Rails core and put into the "Prototype Legacy Helper":http://github.com/rails/prototype_legacy_helper. To get UJS hooks into your HTML, you now pass <tt>:remote => true</tt> instead. For example:
+
+<ruby>
+form_for @post, :remote => true
+</ruby>
+
+Produces:
+
+<html>
+<form action="http://host.com" id="create-post" method="post" data-remote="true">
+</html>
+
+* You no longer need to call <tt>h(string)</tt> to escape HTML output, it is on by default in all view templates. If you want the unescaped string, call <tt>raw(string)</tt>.
+* Helpers now output HTML 5 by default.
+* Form label helper now pulls values from I18n with a single value, so <tt>f.label :name</tt> will pull the <tt>:name</tt> translation.
+* I18n select label on should now be :en.helpers.select instead of :en.support.select.
+* You no longer need to place a minus sign at the end of a ruby interpolation inside an ERb template to remove the trailing carriage return in the HTML output.
+* Added +grouped_collection_select+ helper to Action View.
+* Action View now will raise exceptions if CSS stylesheets and javascript files listed in the +javascript_include_tag+ and +stylesheet_include_tag+ helpers are missing.
+* +content_for?+ has been added allowing you to check for the existence of content in a view before rendering.
+
+
+h3. Active Model
+
+Active Model is new in Rails 3.0. It provides an abstraction layer for any ORM libraries to use to interact with Rails by implementing an Active Model interface.
+
+
+h4. ORM Abstraction and Action Pack Interface
+
+Part of decoupling the core components was extracting all ties to Active Record from Action Pack. This has now been completed. All new ORM plugins now just need to implement Active Model interfaces to work seamlessly with Action Pack.
+
+More Information: - "Make Any Ruby Object Feel Like ActiveRecord":http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/
+
+
+h4. Validations
+
+Validations have been moved from Active Record into Active Model, providing an interface to validations that works across ORM libraries in Rails 3.
+
+* There is now a <tt>validates :attribute, options_hash</tt> shortcut method that allows you to pass options for all the validates class methods, you can pass more than one option to a validate method.
+* The +validates+ method has the following options:
+ * <tt>:acceptance => Boolean</tt>.
+ * <tt>:confirmation => Boolean</tt>.
+ * <tt>:exclusion => { :in => Ennumerable }</tt>.
+ * <tt>:inclusion => { :in => Ennumerable }</tt>.
+ * <tt>:format => { :with => Regexp, :on => :create }</tt>.
+ * <tt>:length => { :maximum => Fixnum }</tt>.
+ * <tt>:numericality => Boolean</tt>.
+ * <tt>:presence => Boolean</tt>.
+ * <tt>:uniqueness => Boolean</tt>.
+
+NOTE: All the Rails version 2.3 style validation methods are still supported in Rails 3.0, the new validates method is designed as an additional aid in your model validations, not a replacement for the existing API.
+
+You can also pass in a validator object, which you can then reuse between objects that use Active Model:
+
+<ruby>
+class TitleValidator < ActiveModel::EachValidator
+ Titles = ['Mr.', 'Mrs.', 'Dr.']
+ def validate_each(record, attribute, value)
+ unless Titles.include?(value)
+ record.errors[attribute] << 'must be a valid title'
+ end
+ end
+end
+</ruby>
+
+<ruby>
+class Person
+ include ActiveModel::Validations
+ attr_accessor :title
+ validates :title, :presence => true, :title => true
+end
+
+# Or for Active Record
+
+class Person < ActiveRecord::Base
+ validates :title, :presence => true, :title => true
+end
+</ruby>
+
+More Information:
+* "Sexy Validation in Rails 3":http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/
+* "Rails 3 Validations Explained":http://lindsaar.net/2010/1/31/validates_rails_3_awesome_is_true
+
+
+h3. Active Record
+
+
+h4. Query Interface
+
+Active Record, through the use of Arel, now returns relations on it's core methods. The existing API in Rails 2.3.x is still supported and will not be deprecated until Rails 3.1 and not removed until Rails 3.2, however, the new API provides the following new methods that all return relations allowing them to be chained together:
+
+* <tt>where</tt> - provides conditions on the relation, what gets returned.
+* <tt>select</tt> - choose what attributes of the models you wish to have returned from the database.
+* <tt>group</tt> - groups the relation on the attribute supplied.
+* <tt>having</tt> - provides an expression limiting group relations (GROUP BY constraint).
+* <tt>joins</tt> - joins the relation to another table.
+* <tt>clause</tt> - provides an expression limiting join relations (JOIN constraint).
+* <tt>includes</tt> - includes other relations pre-loaded.
+* <tt>order</tt> - orders the relation based on the expression supplied.
+* <tt>limit</tt> - limits the relation to the number of records specified.
+* <tt>lock</tt> - locks the records returned from the table.
+* <tt>readonly</tt> - returns an read only copy of the data.
+* <tt>from</tt> - provides a way to select relationships from more than one table.
+* <tt>scope</tt> - (previously +named_scope+) return relations and can be chained together with the other relation methods.
+* <tt>with_scope</tt> - and +with_exclusive_scope+ now also return relations and so can be chained.
+* <tt>default_scope</tt> - also works with relations.
+
+More Information:
+* "Active Record Query Interface":http://m.onkey.org/2010/1/22/active-record-query-interface
+* "Let your SQL Growl in Rails 3":http://hasmanyquestions.wordpress.com/2010/01/17/let-your-sql-growl-in-rails-3/
+
+
+h4. Enhancements
+
+* Added <tt>:destroyed?</tt> to Active Record objects.
+* Added <tt>:inverse_of</tt> to Active Record associations allowing you to pull the instance of an already loaded association without hitting the database.
+
+
+h4. Patches and Deprecations
+
+Additionally, many fixes in the Active Record branch:
+
+* SQLite 2 support has been dropped in favour of SQLite 3.
+* MySQL support for column order.
+* PostgreSQL adapter has had it's +TIME ZONE+ support fixed so it no longer inserts incorrect values.
+* Support multiple schemas in table names for PostgreSQL.
+* PostgreSQL support for the XML data type column.
+* +table_name+ is now cached.
+* A large amount of work done on the Oracle adapter as well with many bug fixes.
+
+As well as the following deprecations:
+
+* +named_scope+ in an Active Record class is deprecated and has been renamed to just +scope+.
+* In +scope+ methods, you should move to using the relation methods, instead of a <tt>:conditions => {}</tt> finder method, for example <tt>scope :since, lambda {|time| where("created_at > ?", time) }</tt>.
+* <tt>save(false)</tt> is deprecated, in favour of <tt>save(:validate => false)</tt>.
+* I18n error messages for ActiveRecord should be changed from :en.activerecord.errors to <tt>:en.errors</tt>.
+* <tt>model.errors.on</tt> is deprecated in favour of <tt>model.errors[]</tt>
+* validates_presence_of => validates... :presence => true
+* <tt>ActiveRecord::Base.colorize_logging</tt> and <tt>config.active_record.colorize_logging</tt> are deprecated in favour of <tt>Rails::Subscriber.colorize_logging</tt> or <tt>config.colorize_logging</tt>
+
+NOTE: while an implementation of State Machine has been in Active Record edge for some months now, it has been removed from the Rails 3.0 release.
+
+
+h3. Active Resource
+
+Active Resource was also extracted out to Active Model allowing you to use Active Resource objects with Action Pack seamlessly.
+
+* Added validations through Active Model.
+* Added observing hooks.
+* HTTP proxy support.
+* Added support for digest authentication.
+* Moved model naming into Active Model.
+* Changed Active Resource attributes to a Hash with indifferent access.
+* Added +first+, +last+ and +all+ aliases for equivalent find scopes.
+* <tt>find_every</tt> now does not return a +ResourceNotFound+ error if nothing returned.
+* Added <tt>save!</tt> which raises <tt>ResourceInvalid</tt> unless the object is <tt>valid?</tt>.
+* <tt>update_attribute</tt> and <tt>update_attributes</tt> added to Active Resource models.
+* Added <tt>exists?</tt>.
+* Renamed <tt>SchemaDefinition</tt> to <tt>Schema</tt> and <tt>define_schema</tt> to <tt>schema</tt>.
+* Use the <tt>format</tt> of Active Resources rather than the <tt>content-type</tt> of remote errors to load errors.
+* Use <tt>instance_eval</tt> for schema block.
+* Fix <tt>ActiveResource::ConnectionError#to_s</tt> when +@response+ does not respond to #code or #message, handles Ruby 1.9 compat.
+* Add support for errors in JSON format.
+* Ensure <tt>load</tt> works with numeric arrays.
+* Recognises a 410 response from remote resource as the resource has been deleted.
+* Add ability to set SSL options on Active Resource connections.
+* Setting connection timeout also affects +Net::HTTP+ <tt>open_timeout</tt>.
+
+Deprecations:
+
+* <tt>save(false)</tt> is deprecated, in favour of <tt>save(:validate => false)</tt>.
+* Ruby 1.9.2: <tt>URI.parse</tt> and <tt>.decode</tt> are deprecated and are no longer used in the library.
+
+
+h3. Active Support
+
+A large effort was made in Active Support to make it cherry pickable, that is, you no longer have to require the entire Active Support library to get pieces of it. This allows the various core components of Rails to run slimmer.
+
+These are the main changes in Active Support:
+
+* Large clean up of the library removing unused methods throughout.
+* Active Support no longer provides vendored versions of "TZInfo":http://tzinfo.rubyforge.org/, "Memcache Client":http://deveiate.org/projects/RMemCache/ and "Builder":http://builder.rubyforge.org/, these are all included as dependencies and installed via the <tt>gem bundle</tt> command.
+* Safe buffers are implemented in <tt>ActiveSupport::SafeBuffer</tt>.
+* Added <tt>Array.uniq_by</tt> and <tt>Array.uniq_by!</tt>.
+* Fixed bug on +TimeZone.seconds_to_utc_offset+ returning wrong value.
+* Added <tt>ActiveSupport::Notifications</tt> middleware.
+* <tt>ActiveSupport.use_standard_json_time_format</tt> now defaults to true.
+* <tt>ActiveSupport.escape_html_entities_in_json</tt> now defaults to false.
+* <tt>Integer#multiple_of?</tt> accepts zero as an argument, returns false unless the receiver is zero.
+* +string.chars+ has been renamed to +string.mb_chars+.
+* +ActiveSupport::OrderedHash+ now can de-serialize through YAML.
+* Added SAX-based parser for XmlMini, using LibXML and Nokogiri.
+* Added <tt>Object#presence</tt> that returns the object if it's <tt>#present?</tt> otherwise returns +nil+.
+* Added <tt>String#exclude?</tt> core extension that returns the inverse of <tt>#include?</tt>.
+* Added <tt>to_i</tt> to +DateTime+ in +ActiveSupport+ so <tt>to_yaml</tt> works correctly on models with +DateTime+ attributes.
+* Added <tt>Enumerable#exclude?</tt> to bring parity to <tt>Enumerable#include?</tt> and avoid if <tt>!x.include?</tt>.
+* Switch to on-by-default XSS escaping for rails.
+* Support deep-merging in +ActiveSupport::HashWithIndifferentAccess+.
+* <tt>Enumerable#sum</tt> now works will all enumerables, even if they don't respond to <tt>:size</tt>.
+* <tt>inspect</tt> on a zero length duration returns '0 seconds' instead of empty string.
+* Add <tt>element</tt> and <tt>collection</tt> to <tt>ModelName</tt>.
+* <tt>String#to_time</tt> and <tt>String#to_datetime</tt> handle fractional seconds.
+* Added support to new callbacks for around filter object that respond to <tt>:before</tt> and <tt>:after</tt> used in before and after callbacks.
+* The <tt>ActiveSupport::OrderedHash#to_a</tt> method returns an ordered set of arrays. Matches Ruby 1.9's <tt>Hash#to_a</tt>.
+* <tt>MissingSourceFile</tt> exists as a constant but it is now just equals to <tt>LoadError</tt>
+* Added <tt>Class#class_attribute</tt>, to be able to declare a class-level attribute whose value is inheritable and overwritable by subclasses.
+* Finally removed +DeprecatedCallbacks+ in <tt>ActiveRecord::Associations</tt>.
+
+The following methods have been removed because they are now available in Ruby 1.8.7 and 1.9.
+
+* <tt>Integer#even?</tt> and <tt>Integer#odd?</tt>
+* <tt>String#each_char</tt>
+* <tt>String#start_with?</tt> and <tt>String#end_with?</tt> (plural aliases still kept)
+* <tt>String#bytesize</tt>
+* <tt>Object#tap</tt>
+* <tt>Symbol#to_proc</tt>
+* <tt>Object#instance_variable_defined?</tt>
+* <tt>Enumerable#none?</tt>
+
+The security patch for REXML remains in Active Support because early patchlevels of Ruby 1.8.7 still need it. Active Support knows whether it has to apply it or not.
+
+The following methods have been removed because they are no longer used in the framework:
+
+* <tt>Class#subclasses</tt>, <tt>Class#reachable?</tt>, <tt>Class#remove_class</tt>
+* <tt>Object#remove_subclasses_of</tt>, <tt>Object#subclasses_of</tt>, <tt>Object#extend_with_included_modules_from</tt>, <tt>Object#extended_by</tt>
+* <tt>Regexp#number_of_captures</tt>
+* <tt>Regexp.unoptionalize</tt>, <tt>Regexp.optionalize</tt>, <tt>Regexp#number_of_captures</tt>
+
+
+h3. Action Mailer
+
+Action Mailer has been given a new API with TMail being replaced out with the new "Mail":http://github.com/mikel/mail as the Email library. Action Mailer itself has been given an almost complete re-write with pretty much every line of code touched. The result is that Action Mailer now simply inherits from Abstract Controller and wraps the Mail gem in a Rails DSL. This reduces the amount of code and duplication of other libraries in Action Mailer considerably.
+
+* All mailers are now in <tt>app/mailers</tt> by default.
+* Can now send email using new API with three methods: +attachments+, +headers+ and +mail+.
+* ActionMailer emailing methods now return Mail::Message objects, which can then be sent the +deliver+ message to send itself.
+* All delivery methods are now abstracted out to the Mail gem.
+* The mail delivery method can accept a hash of all valid mail header fields with their value pair.
+* The mail delivery method acts in a similar way to Action Controller's respond_to block, and you can explicitly or implicitly render templates. Action Mailer will turn the email into a multipart email as needed.
+* You can pass a proc to the <tt>format.mime_type</tt> calls within the mail block and explicitly render specific types of text, or add layouts or different templates. The +render+ call inside the proc is from Abstract Controller, so all the same options are available as they are in Action Controller.
+* What were mailer unit tests have been moved to functional tests.
+
+Deprecations:
+
+* <tt>:charset</tt>, <tt>:content_type</tt>, <tt>:mime_version</tt>, <tt>:implicit_parts_order</tt> are all deprecated in favour of <tt>ActionMailer.default :key => value</tt> style declarations.
+* Mailer dynamic <tt>create_method_name</tt> and <tt>deliver_method_name</tt> are deprecated, just call <tt>method_name</tt> which now returns a <tt>Mail::Message</tt> object.
+* <tt>ActionMailer.deliver(message)</tt> is deprecated, just call <tt>message.deliver</tt>.
+* <tt>template_root</tt> is deprecated, pass options to a render call inside a proc from the <tt>format.mime_type</tt> method inside the <tt>mail</tt> generation block
+* The body method to define instance variables is deprecated (<tt>body {:ivar => value}</tt>), just declare instance variables in the method directly and they will be available in the view.
+* Mailers being in <tt>app/models</tt> is deprecated, use <tt>app/mailers</tt> instead.
+
+More Information:
+* "New Action Mailer API in Rails 3":http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3
+* "New Mail Gem for Ruby":http://lindsaar.net/2010/1/23/mail-gem-version-2-released
+
+
+h3. Credits
+
+See the "full list of contributors to Rails":http://contributors.rubyonrails.org/, many people have spent many hours making Rails 3 what it is. Kudos to all of them.
+
+Rails 3.0 Release Notes were compiled by "Mikel Lindsaar":http://lindsaar.net, who can be found "feeding":http://feeds.feedburner.com/lindsaar-net and "tweeting":http://twitter.com/raasdnil. \ No newline at end of file
diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile
index 46a28da8c4..bedca59c12 100644
--- a/railties/guides/source/action_controller_overview.textile
+++ b/railties/guides/source/action_controller_overview.textile
@@ -625,9 +625,9 @@ class ClientsController < ApplicationController
# returns it. The user will get the PDF as a file download.
def download_pdf
client = Client.find(params[:id])
- send_data(generate_pdf,
+ send_data generate_pdf(client),
:filename => "#{client.name}.pdf",
- :type => "application/pdf")
+ :type => "application/pdf"
end
private
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 3073c3a7a5..fb4c42f118 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -496,7 +496,42 @@ The class method +delegate+
h3. Extensions to +Class+
-h4. Class Attribute Accessors
+h4. Class Attributes
+
+The method +Class#class_attribute+ declares one or more inheritable class attributes that can be overriden at any level down the hierarchy:
+
+<ruby>
+class A
+ class_attribute :x
+end
+
+class B < A; end
+
+class C < B; end
+
+A.x = :a
+B.x # => :a
+C.x # => :a
+
+B.x = :b
+A.x # => :a
+C.x # => :b
+
+C.x = :c
+A.x # => :a
+B.x # => :b
+</ruby>
+
+For example that's the way the +allow_forgery_protection+ flag is implemented for controllers:
+
+<ruby>
+class_attribute :allow_forgery_protection
+self.allow_forgery_protection = true
+</ruby>
+
+For convenience +class_attribute+ defines also a predicate, so that declaration also generates +allow_forgery_protection?+. Such predicate returns the double boolean negation of the value.
+
+NOTE: Defined in +active_support/core_ext/class/attribute.rb+
The macros +cattr_reader+, +cattr_writer+, and +cattr_accessor+ are analogous to their +attr_*+ counterparts but for classes. They initialize a class variable to +nil+ unless it already exists, and generate the corresponding class methods to access it:
@@ -587,82 +622,6 @@ If for whatever reason an application loads the definition of a mailer class and
NOTE: Defined in +active_support/core_ext/class/delegating_attributes.rb+.
-h4. Subclasses
-
-The +subclasses+ method returns the names of all subclasses of a given class as an array of strings. That comprises not only direct subclasses, but all descendants down the hierarchy:
-
-<ruby>
-class C; end
-C.subclasses # => []
-
-Integer.subclasses # => ["Bignum", "Fixnum"]
-
-module M
- class A; end
- class B1 < A; end
- class B2 < A; end
-end
-
-module N
- class C < M::B1; end
-end
-
-M::A.subclasses # => ["N::C", "M::B2", "M::B1"]
-</ruby>
-
-The order in which these class names are returned is unspecified.
-
-See also +Object#subclasses_of+ in "Extensions to All Objects FIX THIS LINK":FIXME.
-
-NOTE: Defined in +active_support/core_ext/class/removal.rb+.
-
-h4. Class Removal
-
-Roughly speaking, the +remove_class+ method removes the class objects passed as arguments:
-
-<ruby>
-Class.remove_class(Hash, Dir) # => [Hash, Dir]
-Hash # => NameError: uninitialized constant Hash
-Dir # => NameError: uninitialized constant Dir
-</ruby>
-
-More specifically, +remove_class+ attempts to remove constants with the same name as the passed class objects from their parent modules. So technically this method does not guarantee the class objects themselves are not still valid and alive somewhere after the method call:
-
-<ruby>
-module M
- class A; end
- class B < A; end
-end
-
-A2 = M::A
-
-M::A.object_id # => 13053950
-Class.remove_class(M::A)
-
-M::B.superclass.object_id # => 13053950 (same object as before)
-A2.name # => "M::A" (name is hard-coded in object)
-</ruby>
-
-WARNING: Removing fundamental classes like +String+ can result in really funky behaviour.
-
-The method +remove_subclasses+ provides a shortcut for removing all descendants of a given class, where "removing" has the meaning explained above:
-
-<ruby>
-class A; end
-class B1 < A; end
-class B2 < A; end
-class C < A; end
-
-A.subclasses # => ["C", "B2", "B1"]
-A.remove_subclasses
-A.subclasses # => []
-C # => NameError: uninitialized constant C
-</ruby>
-
-See also +Object#remove_subclasses_of+ in "Extensions to All Objects FIX THIS LINK":FIXME.
-
-NOTE: Defined in +active_support/core_ext/class/removal.rb+.
-
h3. Extensions to +String+
h4. +squish+
@@ -816,7 +775,15 @@ NOTE: Defined in +active_support/core_ext/integer/inflections.rb+.
h3. Extensions to +Float+
-...
+h4. +round+
+
+The builtin method +Float#round+ rounds a float to the nearest integer. Active Support adds an optional parameter to let you specify a precision:
+
+<ruby>
+Math::E.round(4) # => 2.7183
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/float/rounding.rb+.
h3. Extensions to +BigDecimal+
@@ -1799,20 +1766,11 @@ NOTE: Defined in +active_support/core_ext/name_error.rb+.
h3. Extensions to +LoadError+
-Rails hijacks +LoadError.new+ to return a +MissingSourceFile+ exception:
+Active Support adds +is_missing?+ to +LoadError+, and also assigns that class to the constant +MissingSourceFile+ for backwards compatibility.
-<shell>
-$ ruby -e 'require "nonexistent"'
-...: no such file to load -- nonexistent (LoadError)
-...
-$ script/runner 'require "nonexistent"'
-...: no such file to load -- nonexistent (MissingSourceFile)
-...
-</shell>
-
-The class +MissingSourceFile+ is a subclass of +LoadError+, so any code that rescues +LoadError+ as usual still works as expected. Point is these exception objects respond to +is_missing?+, which given a path name tests whether the exception was raised due to that particular file (except perhaps for the ".rb" extension).
+Given a path name +is_missing?+ tests whether the exception was raised due to that particular file (except perhaps for the ".rb" extension).
-For example, when an action of +PostsController+ is called Rails tries to load +posts_helper.rb+, but that file may not exist. That's fine, the helper module is not mandatory so Rails silences a load error. But it could be the case that the helper module does exist, but it in turn requires another library that is missing. In that case Rails must reraise the exception. The method +is_missing?+ provides a way to distinguish both cases:
+For example, when an action of +PostsController+ is called Rails tries to load +posts_helper.rb+, but that file may not exist. That's fine, the helper module is not mandatory so Rails silences a load error. But it could be the case that the helper module does exist and in turn requires another library that is missing. In that case Rails must reraise the exception. The method +is_missing?+ provides a way to distinguish both cases:
<ruby>
def default_helper_module!
@@ -1820,7 +1778,7 @@ def default_helper_module!
module_path = module_name.underscore
helper module_path
rescue MissingSourceFile => e
- raise e unless e.is_missing? "#{module_path}_helper"
+ raise e unless e.is_missing? "helpers/#{module_path}_helper"
rescue NameError => e
raise e unless e.missing_name? "#{module_name}Helper"
end
diff --git a/railties/guides/source/contributing_to_rails.textile b/railties/guides/source/contributing_to_rails.textile
index 805fcf1a32..1b6823a39a 100644
--- a/railties/guides/source/contributing_to_rails.textile
+++ b/railties/guides/source/contributing_to_rails.textile
@@ -76,21 +76,28 @@ TIP: You may want to "put your git branch name in your shell prompt":http://gith
h4. Set up and Run the Tests
All of the Rails tests must pass with any code you submit, otherwise you have no chance of getting code accepted. This means you need to be able to run the tests. Rails needs the +mocha+ gem for running some tests, so install it with:
+
<shell>
gem install mocha
</shell>
-For the tests that touch the database, this means creating the databases. If you're using MySQL:
+For the tests that touch the database, this means creating test databases. If you're using MySQL, create a user named +rails+ with privileges on the test databases.
+
+<shell>
+mysql> GRANT ALL PRIVILEGES ON activerecord_unittest.*
+ to 'rails'@'localhost';
+mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.*
+ to 'rails'@'localhost';
+</shell>
+
+Enter this from the +activerecord+ directory to create the test databases:
<shell>
-mysql> create database activerecord_unittest;
-mysql> create database activerecord_unittest2;
-mysql> GRANT ALL PRIVILEGES ON activerecord_unittest.*
- to 'rails'@'localhost';
-mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.*
- to 'rails'@'localhost';
+rake mysql:build_databases
</shell>
+NOTE: Using the rake task to create the test databases ensures they have the correct character set and collation.
+
If you’re using another database, check the files under +activerecord/test/connections+ in the Rails source code for default connection information. You can edit these files if you _must_ on your machine to provide different credentials, but obviously you should not push any such changes back to Rails.
Now if you go back to the root of the Rails source on your machine and run +rake+ with no parameters, you should see every test in all of the Rails components pass. If you want to run the all ActiveRecord tests (or just a single one) with another database adapter, enter this from the +activerecord+ directory:
diff --git a/railties/guides/source/credits.textile.erb b/railties/guides/source/credits.textile.erb
index 49e390908f..28c70f2b39 100644
--- a/railties/guides/source/credits.textile.erb
+++ b/railties/guides/source/credits.textile.erb
@@ -43,6 +43,10 @@ p. We'd like to thank the following people for their tireless contributions to t
Cássio Marques is a Brazilian software developer working with different programming languages such as Ruby, JavaScript, CPP and Java, as an independent consultant. He blogs at "/* CODIFICANDO */":http://cassiomarques.wordpress.com, which is mainly written in Portuguese, but will soon get a new section for posts with English translation.
<% end %>
+<% author('James Miller', 'bensie') do %>
+ James Miller is a software developer for "JK Tech":http://www.jk-tech.com in San Diego, CA. Find me on GitHub, Gmail, Twitter, and Freenode as bensie.
+<% end %>
+
<% author('Emilio Tagua', 'miloops') do %>
Emilio Tagua -- a.k.a. miloops -- is an Argentinian entrepreneur, developer, open source contributor and Rails evangelist. Cofounder of "Eventioz":http://eventioz.com. He has been using Rails since 2006 and contributing since early 2008. Can be found at gmail, twitter, freenode, everywhere as miloops.
<% end %>
@@ -50,3 +54,7 @@ p. We'd like to thank the following people for their tireless contributions to t
<% author('Heiko Webers', 'hawe') do %>
Heiko Webers is the founder of "bauland42":http://www.bauland42.de, a German web application security consulting and development company focused on Ruby on Rails. He blogs at the "Ruby on Rails Security Project":http://www.rorsecurity.info. After 10 years of desktop application development, Heiko has rarely looked back.
<% end %>
+
+<% author('Mikel Lindsaar', 'raasdnil') do %>
+ Mikel Lindsaar has been working with Rails since 2006 and is the author of the Ruby Mail gem and core contributor (he helped re-write ActionMailer's API). Mikel has a "blog":http://lindsaar.net/ and "tweets":http://twitter.com/raasdnil.
+<% end %>
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index bd6dbda199..c173748944 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -9,13 +9,13 @@ This guide covers getting up and running with Ruby on Rails. After reading it, y
endprologue.
-WARNING. This Guide is based on Rails 2.3.3. Some of the code shown here will not work in other versions of Rails.
+WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in other versions of Rails.
h3. This Guide Assumes
This guide is designed for beginners who want to get started with a Rails application from scratch. It does not assume that you have any prior experience with Rails. However, to get the most out of it, you need to have some prerequisites installed:
-* The "Ruby":http://www.ruby-lang.org/en/downloads language
+* The "Ruby":http://www.ruby-lang.org/en/downloads language version 1.8.7 or higher
* The "RubyGems":http://rubyforge.org/frs/?group_id=126 packaging system
* A working installation of "SQLite":http://www.sqlite.org (preferred), "MySQL":http://www.mysql.com, or "PostgreSQL":http://www.postgresql.org
@@ -91,7 +91,7 @@ Active Resource provides a framework for managing the connection between busines
h5. Railties
-Railties is the core Rails code that builds new Rails applications and glues the various frameworks together in any Rails application.
+Railties is the core Rails code that builds new Rails applications and glues the various frameworks and plugins together in any Rails application.
h5. Active Support
@@ -134,8 +134,6 @@ NOTE. There are some special circumstances in which you might want to use an alt
* If you're working on Windows, you may find it easier to install Instant Rails. Be aware, though, that "Instant Rails":http://instantrails.rubyforge.org/wiki/wiki.pl releases tend to lag seriously behind the actual Rails version. Also, you will find that Rails development on Windows is overall less pleasant than on other operating systems. If at all possible, we suggest that you install a Linux virtual machine and use that for Rails development, instead of using Windows.
* If you want to keep up with cutting-edge changes to Rails, you'll want to clone the "Rails source code":http://github.com/rails/rails/tree/master from github. This is not recommended as an option for beginners, though.
-WARNING. As of mid-2009, cloning the master branch will get you preliminary Rails 3.0 code. To follow along with this guide, you should clone the 2-3-stable branch instead.
-
h4. Creating the Blog Application
Open a terminal, navigate to a folder where you have rights to create files, and type:
@@ -167,10 +165,13 @@ $ cd blog
In any case, Rails will create a folder in your working directory called <tt>blog</tt>. Open up that folder and explore its contents. Most of the work in this tutorial will happen in the <tt>app/</tt> folder, but here's a basic rundown on the function of each folder that Rails creates in a new application by default:
|_.File/Folder|_.Purpose|
-|README|This is a brief instruction manual for your application. Use it to tell others what your application does, how to set it up, and so on.|
+|Gemfile|This file allows you to specify what gem dependencies are needed for your Rails application.|
+|README.rdoc|This is a brief instruction manual for your application. Use it to tell others what your application does, how to set it up, and so on.|
|Rakefile|This file contains batch jobs that can be run from the terminal.|
|app/|Contains the controllers, models, and views for your application. You'll focus on this folder for the remainder of this guide.|
+|bin/|Holds various executables needed for your Rails application.|
|config/|Configure your application's runtime rules, routes, database, and more.|
+|config.ru|Rack configuration for Rack based servers used to start the application.|
|db/|Shows your current database schema, as well as the database migrations. You'll learn about migrations shortly.|
|doc/|In-depth documentation for your application.|
|lib/|Extended modules for your application (not covered in this guide).|
@@ -179,7 +180,18 @@ In any case, Rails will create a folder in your working directory called <tt>blo
|script/|Scripts provided by Rails to do recurring tasks, such as benchmarking, plugin installation, and starting the console or the web server.|
|test/|Unit tests, fixtures, and other test apparatus. These are covered in "Testing Rails Applications":testing.html|
|tmp/|Temporary files|
-|vendor/|A place for third-party code. In a typical Rails application, this includes Ruby Gems, the Rails source code (if you install it into your project) and plugins containing additional prepackaged functionality.|
+|vendor/|A place for all third-party code. In a typical Rails application, this includes Ruby Gems, the Rails source code (if you install it into your project) and plugins containing additional prepackaged functionality.|
+
+h4. Installing the Required Gems
+
+Rails uses the _Bundler_ gem to populate the +vendor+ directory with all the gems your application depends on. As we don't need any special gems beyond the default, we just need to do the following:
+
+<shell>
+$ gem install bundle
+$ gem bundle
+</shell>
+
+This will copy down the latest versions of all the gems you need to start a rails application.
h4. Configuring a Database
@@ -255,19 +267,11 @@ NOTE. Rake is a general-purpose command-runner that Rails uses for many things.
h3. Hello, Rails!
-One of the traditional places to start with a new language is by getting some text up on screen quickly. To do that in Rails, you need to create at minimum a controller and a view. Fortunately, you can do that in a single command. Enter this command in your terminal:
-
-<shell>
-$ script/generate controller home index
-</shell>
-
-TIP: If you're on Windows, or your Ruby is set up in some non-standard fashion, you may need to explicitly pass Rails +script+ commands to Ruby: +ruby script/generate controller home index+.
+One of the traditional places to start with a new language is by getting some text up on screen quickly, to do this, you need to get your Rails application server running.
-Rails will create several files for you, including +app/views/home/index.html.erb+. This is the template that will be used to display the results of the +index+ action (method) in the +home+ controller. Open this file in your text editor and edit it to contain a single line of code:
+h4. Before we begin
-<code class="html">
-<h1>Hello, Rails!</h1>
-</code>
+As an added help, you can find all the code of this application in a ready to run Git repository at "http://github.com/mikel/getting-started-code":http://github.com/mikel/getting-started-code.
h4. Starting up the Web Server
@@ -283,34 +287,51 @@ This will fire up an instance of the Mongrel web server by default (Rails can al
TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. In development mode, Rails does not generally require you to stop the server; changes you make in files will be automatically picked up by the server.
-The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. To view the page you just created, navigate to +http://localhost:3000/home/index+.
+The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the +About your application’s environment+ link to see a summary of your Application's environment.
+
+h4. Say "Hello", Rails
+
+To get Rails saying "Hello", you need to create at minimum a controller and a view. Fortunately, you can do that in a single command. Enter this command in your terminal:
+
+<shell>
+$ script/generate controller home index
+</shell>
+
+TIP: If you're on Windows, or your Ruby is set up in some non-standard fashion, you may need to explicitly pass Rails +script+ commands to Ruby: +ruby script/generate controller home index+.
+
+Rails will create several files for you, including +app/views/home/index.html.erb+. This is the template that will be used to display the results of the +index+ action (method) in the +home+ controller. Open this file in your text editor and edit it to contain a single line of code:
+
+<code class="html">
+<h1>Hello, Rails!</h1>
+</code>
h4. Setting the Application Home Page
-You'd probably like to replace the "Welcome Aboard" page with your own application's home page. The first step to doing this is to delete the default page from your application:
+Now that we have made the controller and view, we need to tell Rails when we want "Hello Rails" to show up. In our case, we want it to show up when we navigate to the root URL of our site, +http://127.0.0.1:3000/+, instead of the "Welcome Aboard" smoke test.
+
+The first step to doing this is to delete the default page from your application:
<shell>
$ rm public/index.html
</shell>
-Now, you have to tell Rails where your actual home page is located. Open the file +config/routes.rb+ in your editor. This is your application's, _routing file_, which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions. At the bottom of the file you'll see the _default routes_:
+We need to do this as Rails will deliver any static file in the +public+ directory in preference to any dynamic contact we generate from the controllers.
-<ruby>
-map.connect ':controller/:action/:id'
-map.connect ':controller/:action/:id.:format'
-</ruby>
+Now, you have to tell Rails where your actual home page is located. Open the file +config/routes.rb+ in your editor. This is your application's, _routing file_, which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions. There are only comments in this file, so we need to add at the top the following:
-The default routes handle simple requests such as +/home/index+: Rails translates that into a call to the +index+ action in the +home+ controller. As another example, +/posts/edit/1+ would run the +edit+ action in the +posts+ controller with an +id+ of 1.
+<ruby>
+Blog::Application.routes.draw do |map|
-To hook up your home page, you need to add another line to the routing file, above the default routes:
+ root :to => "home#index"
-<ruby>
-map.root :controller => "home"
+ # The priority is based upon order of creation:
+ # first created -> highest priority.
+ #...
</ruby>
-This line illustrates one tiny bit of the "convention over configuration" approach: if you don't specify an action, Rails assumes the +index+ action.
+The +root :to => "home#index"+ tells Rails to map the root action to the home controller's index action.
-Now if you navigate to +http://localhost:3000+ in your browser, you'll see the +home/index+ view.
+Now if you navigate to +http://localhost:3000+ in your browser, you'll see +Hello, Rails!+.
NOTE. For more information about routing, refer to "Rails Routing from the Outside In":routing.html.
@@ -330,28 +351,29 @@ NOTE. While scaffolding will get you up and running quickly, the "one size fits
The scaffold generator will build 14 files in your application, along with some folders, and edit one more. Here's a quick overview of what it creates:
-|_.File |_.Purpose|
-|app/models/post.rb |The Post model|
-|db/migrate/20090113124235_create_posts.rb |Migration to create the posts table in your database (your name will include a different timestamp)|
-|app/views/posts/index.html.erb |A view to display an index of all posts |
-|app/views/posts/show.html.erb |A view to display a single post|
-|app/views/posts/new.html.erb |A view to create a new post|
-|app/views/posts/edit.html.erb |A view to edit an existing post|
-|app/views/layouts/posts.html.erb |A view to control the overall look and feel of the other posts views|
-|public/stylesheets/scaffold.css |Cascading style sheet to make the scaffolded views look better|
-|app/controllers/posts_controller.rb |The Posts controller|
-|test/functional/posts_controller_test.rb |Functional testing harness for the posts controller|
-|app/helpers/posts_helper.rb |Helper functions to be used from the posts views|
-|config/routes.rb |Edited to include routing information for posts|
-|test/fixtures/posts.yml |Dummy posts for use in testing|
-|test/unit/post_test.rb |Unit testing harness for the posts model|
-|test/unit/helpers/posts_helper_test.rb |Unit testing harness for the posts helper|
+|_.File |_.Purpose|
+|app/models/post.rb |The Post model|
+|db/migrate/20100123083454_create_posts.rb |Migration to create the posts table in your database (your name will include a different timestamp)|
+|app/views/posts/index.html.erb| |A view to display an index of all posts |
+|app/views/posts/edit.html.erb |A view to edit an existing post|
+|app/views/posts/show.html.erb |A view to display a single post|
+|app/views/posts/new.html.erb |A view to create a new post|
+|app/views/posts/_form.html.erb |A view to control the overall look and feel of the other posts views|
+|app/views/layouts/posts.html.erb |A view to control the overall look and feel of the other posts views|
+|public/stylesheets/scaffold.css |Cascading style sheet to make the scaffolded views look better|
+|app/controllers/posts_controller.rb |The Posts controller|
+|test/functional/posts_controller_test.rb |Functional testing harness for the posts controller|
+|app/helpers/posts_helper.rb |Helper functions to be used from the posts views|
+|config/routes.rb |Edited to include routing information for posts|
+|test/fixtures/posts.yml |Dummy posts for use in testing|
+|test/unit/post_test.rb |Unit testing harness for the posts model|
+|test/unit/helpers/posts_helper_test.rb |Unit testing harness for the posts helper|
h4. Running a Migration
One of the products of the +script/generate scaffold+ command is a _database migration_. Migrations are Ruby classes that are designed to make it simple to create and modify database tables. Rails uses rake commands to run migrations, and it's possible to undo a migration after it's been applied to your database. Migration filenames include a timestamp to ensure that they're processed in the order that they were created.
-If you look in the +db/migrate/20090113124235_create_posts.rb+ file (remember, yours will have a slightly different name), here's what you'll find:
+If you look in the +db/migrate/20100123083454_create_posts.rb+ file (remember, yours will have a slightly different name), here's what you'll find:
<ruby>
class CreatePosts < ActiveRecord::Migration
@@ -381,6 +403,15 @@ $ rake db:migrate
Remember, you can't run migrations before running +rake db:create+ to create your database, as we covered earlier.
+Rails will execute this migration command and tell you is created the Posts table.
+
+<shell>
+== CreatePosts: migrating =================================================
+-- create_table(:posts)
+ -> 0.0019s
+== CreatePosts: migrated (0.0020s) ========================================
+</shell>
+
NOTE. Because you're working in the development environment by default, this command will apply to the database defined in the +development+ section of your +config/database.yml+ file.
h4. Adding a Link
@@ -423,8 +454,9 @@ Rails includes methods to help you validate the data that you send to models. Op
<ruby>
class Post < ActiveRecord::Base
- validates_presence_of :name, :title
- validates_length_of :title, :minimum => 5
+ validates :name, :presence => true
+ validates :title, :presence => true,
+ :length => { :minimum => 5 }
end
</ruby>
@@ -447,10 +479,9 @@ created_at: nil, updated_at: nil>
>> p.save
=> false
>> p.errors
-=> #<ActiveRecord::Errors:0x23bcf0c @base=#<Post id: nil, name: nil,
-title: nil, content: "A new post", created_at: nil, updated_at: nil>,
-@errors={"name"=>["can't be blank"], "title"=>["can't be blank",
-"is too short (minimum is 5 characters)"]}>
+=> #<OrderedHash {:title=>["can't be blank",
+ "is too short (minimum is 5 characters)"],
+ :name=>["can't be blank"]}>
</shell>
This code shows creating a new +Post+ instance, attempting to save it and getting +false+ for a return value (indicating that the save failed), and inspecting the +errors+ of the post.
@@ -472,7 +503,7 @@ def index
end
</ruby>
-This code sets the +@posts+ instance variable to an array of all posts in the database. +Post.find(:all)+ or +Post.all+ calls the +Post+ model to return all of the posts that are currently in the database, with no limiting conditions.
+This code sets the +@posts+ instance variable to an array of all posts in the database. +Post.all+ calls the +Post+ model to return all of the posts that are currently in the database, with no limiting conditions.
TIP: For more information on finding records with Active Record, see "Active Record Query Interface":active_record_querying.html.
@@ -486,17 +517,19 @@ The +respond_to+ block handles both HTML and XML calls to this action. If you br
<th>Name</th>
<th>Title</th>
<th>Content</th>
+ <th></th>
+ <th></th>
+ <th></th>
</tr>
<% @posts.each do |post| %>
<tr>
- <td><%=h post.name %></td>
- <td><%=h post.title %></td>
- <td><%=h post.content %></td>
+ <td><%= post.name %></td>
+ <td><%= post.title %></td>
+ <td><%= post.content %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
- <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?',
- :method => :delete %></td>
+ <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
@@ -508,10 +541,11 @@ The +respond_to+ block handles both HTML and XML calls to this action. If you br
This view iterates over the contents of the +@posts+ array to display content and links. A few things to note in the view:
-* +h+ is a Rails helper method to sanitize displayed data, preventing cross-site scripting attacks
* +link_to+ builds a hyperlink to a particular destination
* +edit_post_path+ is a helper that Rails provides as part of RESTful routing. You'll see a variety of these helpers for the different actions that the controller includes.
+NOTE. In previous versions of Rails, you had to use +<%=h post.name %>+ so that any HTML would be escaped before being inserted into the page. In Rails 3.0, this is now the default. To get unescaped HTML, you now use +<%= raw post.name %>+.
+
TIP: For more details on the rendering process, see "Layouts and Rendering in Rails":layouts_and_rendering.html.
h4. Customizing the Layout
@@ -519,21 +553,17 @@ h4. Customizing the Layout
The view is only part of the story of how HTML is displayed in your web browser. Rails also has the concept of +layouts+, which are containers for views. When Rails renders a view to the browser, it does so by putting the view's HTML into a layout's HTML. The +script/generate scaffold+ command automatically created a default layout, +app/views/layouts/posts.html.erb+, for the posts. Open this layout in your editor and modify the +body+ tag:
<erb>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!DOCTYPE html>
+<html>
<head>
- <meta http-equiv="content-type"
- content="text/html;charset=UTF-8" />
<title>Posts: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body style="background: #EEEEEE;">
-<p style="color: green"><%= flash[:notice] %></p>
+<p class="notice"><%= notice %></p>
-<%= yield %>
+<%= yield %>
</body>
</html>
@@ -561,34 +591,48 @@ The +new.html.erb+ view displays this empty Post to the user:
<erb>
<h1>New post</h1>
+<%= render 'form' %>
+
+<%= link_to 'Back', posts_path %>
+</erb>
+
+The +<%= render 'form' %>+ line is our first introduction to _partials_ in Rails. A partial is a snippet of HTML and Ruby code that can be reused in multiple locations. In this case, the form used to make a new post, is very similar to a form used to edit a post, both have text fields for the name and title and a text area for the content with a button to make a new post or update the existing post.
+
+If you take a look at +views/posts/_form.html.erb+ file, you will see the following:
+
+<erb>
<% form_for(@post) do |f| %>
<%= f.error_messages %>
- <p>
+ <div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
- </p>
- <p>
+ </div>
+ <div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
- </p>
- <p>
+ </div>
+ <div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
- </p>
- <p>
- <%= f.submit "Create" %>
- </p>
+ </div>
+ <div class="actions">
+ <%= f.submit %>
+ </div>
<% end %>
-
-<%= link_to 'Back', posts_path %>
</erb>
+This partial receives all the instance variables defined in the calling view file, so in this case, the controller assigned the new Post object to +@post+ and so, this is available in both the view and partial as +@post+.
+
+For more information on partials, refer to the "Layouts and Rendering in Rails":layouts_and_rendering.html#using-partials guide.
+
The +form_for+ block is used to create an HTML form. Within this block, you have access to methods to build various controls on the form. For example, +f.text_field :name+ tells Rails to create a text input on the form, and to hook it up to the +name+ attribute of the instance being displayed. You can only use these methods with attributes of the model that the form is based on (in this case +name+, +title+, and +content+). Rails uses +form_for+ in preference to having you write raw HTML because the code is more succinct, and because it explicitly ties the form to a particular model instance.
+The +form_for+ block is also smart enough to work out if you are doing a _New Post_ or an _Edit Post_ action, and will set the form +action+ tags and submit button names appropriately in the HTML output.
+
TIP: If you need to create an HTML form that displays arbitrary fields, not tied to a model, you should use the +form_tag+ method, which provides shortcuts for building forms that are not necessarily tied to a model instance.
-When the user clicks the +Create+ button on this form, the browser will send information back to the +create+ method of the controller (Rails knows to call the +create+ method because the form is sent with an HTTP POST request; that's one of the conventions that I mentioned earlier):
+When the user clicks the +Create Post+ button on this form, the browser will send information back to the +create+ method of the controller (Rails knows to call the +create+ method because the form is sent with an HTTP POST request; that's one of the conventions that I mentioned earlier):
<ruby>
def create
@@ -596,22 +640,24 @@ def create
respond_to do |format|
if @post.save
- flash[:notice] = 'Post was successfully created.'
- format.html { redirect_to(@post) }
- format.xml { render :xml => @post, :status => :created,
- :location => @post }
+ format.html { redirect_to(@post,
+ :notice => 'Post was successfully created.') }
+ format.xml { render :xml => @post,
+ :status => :created, :location => @post }
else
format.html { render :action => "new" }
format.xml { render :xml => @post.errors,
- :status => :unprocessable_entity }
+ :status => :unprocessable_entity }
end
end
end
</ruby>
-The +create+ action instantiates a new Post object from the data supplied by the user on the form, which Rails makes available in the +params+ hash. After saving the new post, it uses +flash[:notice]+ to create an informational message for the user, and redirects to the show action for the post. If there's any problem, the +create+ action just shows the +new+ view a second time, with any error messages.
+The +create+ action instantiates a new Post object from the data supplied by the user on the form, which Rails makes available in the +params+ hash. After successfully saving the new post, returns the appropriate format that the user has requested (HTML in our case). It then redirects the user to the resulting post +show+ action and sets a notice to the user that the Post was successfully created.
-Rails provides the +flash+ hash (usually just called the Flash) so that messages can be carried over to another action, providing the user with useful information on the status of their request. In the case of +create+, the user never actually sees any page rendered during the Post creation process, because it immediately redirects to the new Post as soon Rails saves the record. The Flash carries over a message to the next action, so that when the user is redirected back to the +show+ action, they are presented with a message saying "Post was successfully created."
+If the post was not successfully saved, due to a validation error, then the controller returns the user back to the +new+ action with any error messages so that the user has the chance to fix the error and try again.
+
+The "Post was successfully created" message is stored inside of the Rails +flash+ hash, (usually just called the Flash) so that messages can be carried over to another action, providing the user with useful information on the status of their request. In the case of +create+, the user never actually sees any page rendered during the Post creation process, because it immediately redirects to the new Post as soon Rails saves the record. The Flash carries over a message to the next action, so that when the user is redirected back to the +show+ action, they are presented with a message saying "Post was successfully created."
h4. Showing an Individual Post
@@ -633,17 +679,17 @@ The +show+ action uses +Post.find+ to search for a single record in the database
<erb>
<p>
<b>Name:</b>
- <%=h @post.name %>
+ <%= @post.name %>
</p>
<p>
<b>Title:</b>
- <%=h @post.title %>
+ <%= @post.title %>
</p>
<p>
<b>Content:</b>
- <%=h @post.content %>
+ <%= @post.content %>
</p>
@@ -666,30 +712,15 @@ After finding the requested post, Rails uses the +edit.html.erb+ view to display
<erb>
<h1>Editing post</h1>
-<% form_for(@post) do |f| %>
- <%= f.error_messages %>
-
- <p>
- <%= f.label :name %><br />
- <%= f.text_field :name %>
- </p>
- <p>
- <%= f.label :title %><br />
- <%= f.text_field :title %>
- </p>
- <p>
- <%= f.label :content %><br />
- <%= f.text_area :content %>
- </p>
- <p>
- <%= f.submit "Update" %>
- </p>
-<% end %>
+<%= render 'form' %>
<%= link_to 'Show', @post %> |
<%= link_to 'Back', posts_path %>
+<% end %>
</erb>
+Again, as with the +new+ action, the +edit+ action is using the +form+ partial, this time however, the form will do a PUT action to the PostsController and the submit button will display "Update Post"
+
Submitting the form created by this view will invoke the +update+ action within the controller:
<ruby>
@@ -698,13 +729,13 @@ def update
respond_to do |format|
if @post.update_attributes(params[:post])
- flash[:notice] = 'Post was successfully updated.'
- format.html { redirect_to(@post) }
+ format.html { redirect_to(@post,
+ :notice => 'Post was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @post.errors,
- :status => :unprocessable_entity }
+ :status => :unprocessable_entity }
end
end
end
@@ -712,8 +743,6 @@ end
In the +update+ action, Rails first uses the +:id+ parameter passed back from the edit view to locate the database record that's being edited. The +update_attributes+ call then takes the rest of the parameters from the request and applies them to this record. If all goes well, the user is redirected to the post's +show+ view. If there are any problems, it's back to +edit+ to correct them.
-NOTE. Sharp-eyed readers will have noticed that the +form_for+ declaration is identical for the +new+ and +edit+ views. Rails generates different code for the two forms because it's smart enough to notice that in the one case it's being passed a new record that has never been saved, and in the other case an existing record that has already been saved to the database. In a production Rails application, you would ordinarily eliminate this duplication by moving identical code to a _partial template_, which you could then include in both parent templates. But the scaffold generator tries not to make too many assumptions, and generates code that's easy to modify if you want different forms for +create+ and +edit+.
-
h4. Destroying a Post
Finally, clicking one of the +destroy+ links sends the associated id to the +destroy+ action:
@@ -734,60 +763,7 @@ The +destroy+ method of an Active Record model instance removes the correspondin
h3. DRYing up the Code
-At this point, it's worth looking at some of the tools that Rails provides to eliminate duplication in your code. In particular, you can use _partials_ to clean up duplication in views and _filters_ to help with duplication in controllers.
-
-h4. Using Partials to Eliminate View Duplication
-
-As you saw earlier, the scaffold-generated views for the +new+ and +edit+ actions are largely identical. You can pull the shared code out into a partial template. This requires editing the new and edit views, and adding a new template. The new +_form.html.erb+ template should be saved in the same +app/views/posts+ folder as the files from which it is being extracted. Note that the name of this file begins with an underscore; that's the Rails naming convention for partial templates.
-
-<tt>new.html.erb</tt>:
-
-<erb>
-<h1>New post</h1>
-
-<%= render :partial => "form" %>
-
-<%= link_to 'Back', posts_path %>
-</erb>
-
-<tt>edit.html.erb</tt>:
-
-<erb>
-<h1>Editing post</h1>
-
-<%= render :partial => "form" %>
-
-<%= link_to 'Show', @post %> |
-<%= link_to 'Back', posts_path %>
-</erb>
-
-<tt>_form.html.erb</tt>:
-
-<erb>
-<% form_for(@post) do |f| %>
- <%= f.error_messages %>
-
- <p>
- <%= f.label :name %><br />
- <%= f.text_field :name %>
- </p>
- <p>
- <%= f.label :title, "title" %><br />
- <%= f.text_field :title %>
- </p>
- <p>
- <%= f.label :content %><br />
- <%= f.text_area :content %>
- </p>
- <p>
- <%= f.submit "Save" %>
- </p>
-<% end %>
-</erb>
-
-Now, when Rails renders the +new+ or +edit+ view, it will insert the +_form+ partial at the indicated point. Note the naming convention for partials: if you refer to a partial named +form+ inside of a view, the corresponding file is +_form.html.erb+, with a leading underscore.
-
-For more information on partials, refer to the "Layouts and Rendering in Rails":layouts_and_rendering.html#using-partials guide.
+At this point, it's worth looking at some of the tools that Rails provides to eliminate duplication in your code. In particular, you can use _partials_ to clean up duplication in views (as you saw above with the +new+ and +edit+ views both sharing the +form+ partial) and _filters_ to help with duplication in controllers.
h4. Using Filters to Eliminate Controller Duplication
@@ -859,14 +835,13 @@ h4. Generating a Model
Models in Rails use a singular name, and their corresponding database tables use a plural name. For the model to hold comments, the convention is to use the name Comment. Even if you don't want to use the entire apparatus set up by scaffolding, most Rails developers still use generators to make things like models and controllers. To create the new model, run this command in your terminal:
<shell>
-$ script/generate model Comment commenter:string body:text
- post:references
+$ script/generate model Comment commenter:string body:text post:references
</shell>
This command will generate four files:
* +app/models/comment.rb+ - The model
-* +db/migrate/20091013214407_create_comments.rb+ - The migration
+* +db/migrate/20100124023310_create_comments.rb+ - The migration
* +test/unit/comment_test.rb+ and +test/fixtures/comments.yml+ - The test harness.
First, take a look at +comment.rb+:
@@ -905,7 +880,14 @@ The +t.references+ line sets up a foreign key column for the association between
$ rake db:migrate
</shell>
-Rails is smart enough to only execute the migrations that have not already been run against the current database.
+Rails is smart enough to only execute the migrations that have not already been run against the current database, so in this case you will just see:
+
+<shell>
+== CreateComments: migrating =================================================
+-- create_table(:comments)
+ -> 0.0019s
+== CreateComments: migrated (0.0020s) ========================================
+</shell>
h4. Associating Models
@@ -926,8 +908,9 @@ You'll need to edit the +post.rb+ file to add the other side of the association:
<ruby>
class Post < ActiveRecord::Base
- validates_presence_of :name, :title
- validates_length_of :title, :minimum => 5
+ validates :name, :presence => true
+ validates :title, :presence => true,
+ :length => { :minimum => 5 }
has_many :comments
end
</ruby>
@@ -936,12 +919,14 @@ These two declarations enable a good bit of automatic behavior. For example, if
TIP: For more information on Active Record associations, see the "Active Record Associations":association_basics.html guide.
-h4. Adding a Route
+h4. Adding a Route for Comments
-_Routes_ are entries in the +config/routes.rb+ file that tell Rails how to match incoming HTTP requests to controller actions. Open up that file and find the existing line referring to +posts+ (it will be right at the top of the file). Then edit it as follows:
+As with the +home+ controller, we will need to add a route so that Rails knows where we would like to navigate to see +comments+. Open up the +config/routes.rb+ file again, you will see an entry that was added automatically for +posts+ near the top by the scaffold generator, +resources :posts+, edit it as follows:
<ruby>
-map.resources :posts, :has_many => :comments
+resources :posts do
+ resources :comments
+end
</ruby>
This creates +comments+ as a _nested resource_ within +posts+. This is another part of capturing the hierarchical relationship that exists between posts and comments.
@@ -1063,20 +1048,19 @@ The +views/comments/index.html.erb+ view:
<tr>
<th>Commenter</th>
<th>Body</th>
+ <th></th>
+ <th></th>
+ <th></th>
</tr>
-<% for comment in @comments %>
+<% @comments.each do |comment| %>
<tr>
- <td><%=h comment.commenter %></td>
- <td><%=h comment.body %></td>
+ <td><%= comment.commenter %></td>
+ <td><%= comment.body %></td>
<td><%= link_to 'Show', post_comment_path(@post, comment) %></td>
- <td>
- <%= link_to 'Edit', edit_post_comment_path(@post, comment) %>
- </td>
- <td>
- <%= link_to 'Destroy', post_comment_path(@post, comment),
- :confirm => 'Are you sure?', :method => :delete %>
- </td>
+ <td><%= link_to 'Edit', edit_post_comment_path(@post, comment) %></td>
+ <td><%= link_to 'Destroy', post_comment_path(@post, comment),
+ :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
@@ -1087,28 +1071,45 @@ The +views/comments/index.html.erb+ view:
<%= link_to 'Back to Post', @post %>
</erb>
-The +views/comments/new.html.erb+ view:
+The +views/comments/new.html.erb+ view (again using a partial to render a form that is shared with the +edit+ view):
<erb>
<h1>New comment</h1>
+<%= render 'form' %>
+
+<%= link_to 'Back', post_comments_path(@post) %>
+</erb>
+
+The +views/comments/edit.html.erb+ view:
+
+<erb>
+<h1>Editing comment</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', post_comment_path(@post, @comment) %> |
+<%= link_to 'Back', post_comments_path(@post) %>
+</erb>
+
+The +views/comments/_form.html.erb+ partial:
+
+<erb>
<% form_for([@post, @comment]) do |f| %>
<%= f.error_messages %>
- <p>
+ <div class="field">
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
- </p>
- <p>
+ </div>
+ <div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
- </p>
- <p>
- <%= f.submit "Create" %>
- </p>
+ </div>
+ <div class="actions">
+ <%= f.submit %>
+ </div>
<% end %>
-
-<%= link_to 'Back', post_comments_path(@post) %>
</erb>
The +views/comments/show.html.erb+ view:
@@ -1118,43 +1119,18 @@ The +views/comments/show.html.erb+ view:
<p>
<b>Commenter:</b>
- <%=h @comment.commenter %>
+ <%= @comment.commenter %>
</p>
<p>
<b>Comment:</b>
- <%=h @comment.body %>
+ <%= @comment.body %>
</p>
<%= link_to 'Edit', edit_post_comment_path(@post, @comment) %> |
<%= link_to 'Back', post_comments_path(@post) %>
</erb>
-The +views/comments/edit.html.erb+ view:
-
-<erb>
-<h1>Editing comment</h1>
-
-<% form_for([@post, @comment]) do |f| %>
- <%= f.error_messages %>
-
- <p>
- <%= f.label :commenter %><br />
- <%= f.text_field :commenter %>
- </p>
- <p>
- <%= f.label :body %><br />
- <%= f.text_area :body %>
- </p>
- <p>
- <%= f.submit "Update" %>
- </p>
-<% end %>
-
-<%= link_to 'Show', post_comment_path(@post, @comment) %> |
-<%= link_to 'Back', post_comments_path(@post) %>
-</erb>
-
Again, the added complexity here (compared to the views you saw for managing posts) comes from the necessity of juggling a post and its comments at the same time.
h4. Hooking Comments to Posts
@@ -1164,29 +1140,29 @@ As a next step, I'll modify the +views/posts/show.html.erb+ view to show the com
<erb>
<p>
<b>Name:</b>
- <%=h @post.name %>
+ <%= @post.name %>
</p>
<p>
<b>Title:</b>
- <%=h @post.title %>
+ <%= @post.title %>
</p>
<p>
<b>Content:</b>
- <%=h @post.content %>
+ <%= @post.content %>
</p>
<h2>Comments</h2>
-<% @post.comments.each do |c| %>
+<% @post.comments.each do |comment| %>
<p>
<b>Commenter:</b>
- <%=h c.commenter %>
+ <%= comment.commenter %>
</p>
<p>
<b>Comment:</b>
- <%=h c.body %>
+ <%= comment.body %>
</p>
<% end %>
@@ -1203,21 +1179,22 @@ If you decide at some point to delete a post, you likely want to delete the comm
<ruby>
class Post < ActiveRecord::Base
- validates_presence_of :name, :title
- validates_length_of :title, :minimum => 5
+ validates :name, :presence => true
+ validates :title, :presence => true,
+ :length => { :minimum => 5 }
has_many :comments, :dependent => :destroy
end
</ruby>
h3. Building a Multi-Model Form
-Comments and posts are edited on two separate forms - which makes sense, given the flow of this mini-application. But what if you want to edit more than one thing on a single form? Rails 2.3 offers new support for nested forms. Let's add support for giving each post multiple tags, right in the form where you create the post. First, create a new model to hold the tags:
+Comments and posts are edited on two separate forms - which makes sense, given the flow of this mini-application. But what if you want to edit more than one thing on a single form? Rails offers support for nested forms. Let's add support for giving each post multiple tags, right in the form where you create the post. First, create a new model to hold the tags:
<shell>
$ script/generate model tag name:string post:references
</shell>
-Run the migration to create the database table:
+Again, run the migration to create the database table:
<shell>
$ rake db:migrate
@@ -1227,8 +1204,9 @@ Next, edit the +post.rb+ file to create the other side of the association, and t
<ruby>
class Post < ActiveRecord::Base
- validates_presence_of :name, :title
- validates_length_of :title, :minimum => 5
+ validates :name, :presence => true
+ validates :title, :presence => true,
+ :length => { :minimum => 5 }
has_many :comments
has_many :tags
@@ -1242,51 +1220,53 @@ The +:allow_destroy+ option on the nested attribute declaration tells Rails to d
You'll also need to modify +views/posts/_form.html.erb+ to include the tags:
<erb>
-<% @post.tags.build if @post.tags.empty? %>
+<% @post.tags.build %>
<% form_for(@post) do |post_form| %>
<%= post_form.error_messages %>
- <p>
+ <div class="field">
<%= post_form.label :name %><br />
<%= post_form.text_field :name %>
- </p>
- <p>
- <%= post_form.label :title, "Title" %><br />
+ </div>
+ <div class="field">
+ <%= post_form.label :title %><br />
<%= post_form.text_field :title %>
- </p>
- <p>
+ </div>
+ <div class="field">
<%= post_form.label :content %><br />
<%= post_form.text_area :content %>
- </p>
+ </div>
<h2>Tags</h2>
<% post_form.fields_for :tags do |tag_form| %>
- <p>
+ <div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
- </p>
+ </div>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
- <p>
- <%= tag_form.label :_delete, 'Remove:' %>
- <%= tag_form.check_box :_delete %>
- </p>
+ <div class="field">
+ <%= tag_form.label :_destroy, 'Remove:' %>
+ <%= tag_form.check_box :_destroy %>
+ </div>
<% end %>
<% end %>
- <p>
- <%= post_form.submit "Save" %>
- </p>
+ <div class="actions">
+ <%= post_form.submit %>
+ </div>
<% end %>
</erb>
+You will note that we also have changed the +form_for(@post) do |f|+ to +form_for(@post) do |post_form|+ and changed all the +f+ method calls as well to show more clearly what is going on.
+
With these changes in place, you'll find that you can edit a post and its tags directly on the same view.
-NOTE. You may want to use JavaScript to dynamically add additional tags on a single form. For an example of this and other advanced techniques, see the "complex form examples application":http://github.com/alloy/complex-form-examples/tree/master.
+NOTE. You may want to use JavaScript to dynamically add additional tags on a single form. For an example of this and other advanced techniques, see the "complex form examples application":http://github.com/mikel/complex-form-examples/.
h3. What's Next?
Now that you've seen your first Rails application, you should feel free to update it and experiment on your own. But you don't have to do everything without help. As you need assistance getting up and running with Rails, feel free to consult these support resources:
-* The "Ruby On Rails guides":http://guides.rubyonrails.org
+* The "Ruby On Rails guides":http://guides.rails.info
* The "Ruby on Rails mailing list":http://groups.google.com/group/rubyonrails-talk
* The "#rubyonrails":irc://irc.freenode.net/#rubyonrails channel on irc.freenode.net
* The "Rails Wiki":http://wiki.rubyonrails.org/
@@ -1300,6 +1280,7 @@ h3. Changelog
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/2
+* January 24, 2010: Re-write for Rails 3.0 by "Mikel Lindsaar":credits:html#raasdnil
* July 18, 2009: Minor cleanup in anticipation of Rails 2.3.3 by "Mike Gunderloy":credits.html#mgunderloy
* February 1, 2009: Updated for Rails 2.3 by "Mike Gunderloy":credits.html#mgunderloy
* November 3, 2008: Formatting patch from Dave Rothlisberger
@@ -1307,4 +1288,4 @@ h3. Changelog
* October 16, 2008: Revised based on feedback from Pratik Naik by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
* October 13, 2008: First complete draft by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
* October 12, 2008: More detail, rearrangement, editing by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication)
-* September 8, 2008: initial version by James Miller (not yet approved for publication)
+* September 8, 2008: initial version by "James Miller":credits.html#bensie (not yet approved for publication)
diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile
index 0cee413ac3..2cb98e9ee6 100644
--- a/railties/guides/source/layouts_and_rendering.textile
+++ b/railties/guides/source/layouts_and_rendering.textile
@@ -27,21 +27,74 @@ I'll cover each of these methods in turn. But first, a few words about the very
h4. Rendering by Default: Convention Over Configuration in Action
-You've heard that Rails promotes "convention over configuration." Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to actions. For example, if you have this code in your +BooksController+ class:
+You've heard that Rails promotes "convention over configuration." Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your +BooksController+ class:
<ruby>
-def show
- @book = Book.find(params[:id])
+class BooksController < ApplicationController
+end
+</ruby>
+
+And the following in your routes file:
+
+<ruby>
+resources :books
+</ruby>
+
+And you have a view file +app/views/books/index.html.erb+:
+
+<ruby>
+<h1>Books are coming soon!</h1>
+</ruby>
+
+Rails will automatically render +app/views/books/index.html.erb+ when you navigate to +/books+ and you will see on your screen that "Books are coming soon!"
+
+However a coming soon screen is only minimally useful, so you will soon create your +Book+ model and add the index action to +BooksController+:
+
+<ruby>
+class BooksController < ApplicationController
+ def index
+ @books = Book.all
+ end
end
</ruby>
-Rails will automatically render +app/views/books/show.html.erb+ after running the method. In fact, if you have the default catch-all route in place (+map.connect ':controller/:action/:id'+), Rails will even render views that don't have any code at all in the controller. For example, if you have the default route in place and a request comes in for +/books/sale_list+, Rails will render +app/views/books/sale_list.html.erb+ in response.
+Note that again, we have convention over configuration, in that there is no explicit render at the end of this index action. The rule is that if you do not explicitly render something by the end of the controller action, rails will look for the +action_name.html.erb+ template in the controllers view path and then render that, so in this case, Rails will render the +app/views/books/index.html.erb+ file.
-NOTE: The actual rendering is done by subclasses of +ActionView::TemplateHandlers+. This guide does not dig into that process, but it's important to know that the file extension on your view controls the choice of template handler. In Rails 2, the standard extensions are +.erb+ for ERB (HTML with embedded Ruby), +.rjs+ for RJS (javascript with embedded ruby) and +.builder+ for Builder (XML generator). You'll also find +.rhtml+ used for ERB templates and +.rxml+ for Builder templates, but those extensions are now formally deprecated and will be removed from a future version of Rails.
+So in our view, we want to display the properties of all the books, we could do this with an ERB template like this:
+
+<ruby>
+<h1>Listing Books</h1>
+
+<table>
+ <tr>
+ <th>Title</th>
+ <th>Summary</th>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @books.each do |book| %>
+ <tr>
+ <td><%= book.title %></td>
+ <td><%= book.content %></td>
+ <td><%= link_to 'Show', book %></td>
+ <td><%= link_to 'Edit', edit_book_path(book) %></td>
+ <td><%= link_to 'Remove', book, :confirm => 'Are you sure?', :method => :delete %></td>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New book', new_book_path %>
+</ruby>
+
+NOTE: The actual rendering is done by subclasses of +ActionView::TemplateHandlers+. This guide does not dig into that process, but it's important to know that the file extension on your view controls the choice of template handler. In Rails 2, the standard extensions are +.erb+ for ERB (HTML with embedded Ruby), +.rjs+ for RJS (javascript with embedded ruby) and +.builder+ for Builder (XML generator).
h4. Using +render+
-In most cases, the +ActionController::Base#render+ method does the heavy lifting of rendering your application's content for use by a browser. There are a variety of ways to customize the behavior of +render+. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well.
+In most cases, the +ActionController::Base#render+ method does the heavy lifting of rendering your application's content for use by a browser. There are a variety of ways to customise the behaviour of +render+. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well.
TIP: If you want to see the exact results of a call to +render+ without needing to inspect it in a browser, you can call +render_to_string+. This method takes exactly the same options as +render+, but it returns a string instead of sending a response back to the browser.
@@ -53,7 +106,24 @@ Perhaps the simplest thing you can do with +render+ is to render nothing at all:
render :nothing => true
</ruby>
-This will send an empty response to the browser (though it will include any status headers you set with the :status option, discussed below).
+If you look at the response for this using Curl you will see the following:
+
+<shell>
+ $ curl -i 127.0.0.1:3000/books
+HTTP/1.1 200 OK
+Connection: close
+Date: Sun, 24 Jan 2010 09:25:18 GMT
+Transfer-Encoding: chunked
+Content-Type: */*; charset=utf-8
+X-Runtime: 0.014297
+Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
+Cache-Control: no-cache
+
+
+ $
+</shell>
+
+We see there is an empty response (no data after the +Cache-Control+ line), but that Rails has set the response to 200 OK, so the request was successful. You can set the +:status+ options on render to change this response. Rendering nothing can be useful for AJAX requests where all you want to send back to the browser is an acknowledgement that the request was completed.
TIP: You should probably be using the +head+ method, discussed later in this guide, instead of +render :nothing+. This provides additional flexibility and makes it explicit that you're only generating HTTP headers.
@@ -73,7 +143,7 @@ def update
end
</ruby>
-If the call to +update_attributes+ fails, calling the +update+ action in this controller will render the +edit.html.erb+ template belonging to the same controller.
+If the call to +update_attributes+ fails, calling the +update+ action in this controller will render the +edit.html.erb+ template belonging to the same controller.
If you prefer, you can use a symbol instead of a string to specify the action to render:
@@ -89,7 +159,7 @@ def update
end
</ruby>
-To be explicit, you can use +render+ with the +:action+ option (though this is no longer necessary as of Rails 2.3):
+To be explicit, you can use +render+ with the +:action+ option (though this is no longer necessary in Rails 3.0):
<ruby>
def update
@@ -140,6 +210,31 @@ NOTE: By default, the file is rendered without using the current layout. If you
TIP: If you're running on Microsoft Windows, you should use the +:file+ option to render a file, because Windows filenames do not have the same format as Unix filenames.
+h5. Wrapping it up
+
+The above three methods of render (rendering another template within the controller, rendering a template within another controller and rendering an arbitrary file on the file system) are actually all variants of the same action.
+
+In fact, in the BooksController method, inside of the edit action where we want to render the edit template if the book does not update successfully, all of the following render calls would all render the +edit.html.erb+ template in the +views/books+ directory:
+
+<ruby>
+render :edit
+render :action => :edit
+render 'edit'
+render 'edit.html.erb'
+render :action => 'edit'
+render :action => 'edit.html.erb'
+render 'books/edit'
+render 'books/edit.html.erb'
+render :template => 'books/edit'
+render :template => 'books/edit.html.erb'
+render '/path/to/rails/app/views/books/edit'
+render '/path/to/rails/app/views/books/edit.html.erb'
+render :file => '/path/to/rails/app/views/books/edit'
+render :file => '/path/to/rails/app/views/books/edit.html.erb'
+</ruby>
+
+Which one you use is really a matter of style and convention, but the rule of thumb is to use the simplest one that makes sense for the code you are writing.
+
h5. Using +render+ with +:inline+
The +render+ method can do without a view completely, if you're willing to use the +:inline+ option to supply ERB as part of the method call. This is perfectly valid:
@@ -180,7 +275,7 @@ render :text => "OK"
TIP: Rendering pure text is most useful when you're responding to AJAX or web service requests that are expecting something other than proper HTML.
-NOTE: By default, if you use the +:text+ option, the file is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the +:layout => true+ option
+NOTE: By default, if you use the +:text+ option the text is rendered without using the current layout. If you want Rails to put the text into the current layout, you need to add the +:layout => true+ option.
h5. Rendering JSON
@@ -314,21 +409,21 @@ end
Now, if the current user is a special user, they'll get a special layout when viewing a product. You can even use an inline method to determine the layout:
+You can also decide the layout by passing a Proc object, the block you give the Proc will be given the +controller+ instance, so you can make decisions based on the current request. For example:
+
<ruby>
class ProductsController < ApplicationController
- layout proc { |controller| controller.request.xhr? ? 'popup' : 'application' }
- # ...
+ layout Proc.new { |controller| controller.request.xhr? ? 'popup' : 'application' }
end
</ruby>
h6. Conditional Layouts
-Layouts specified at the controller level support +:only+ and +:except+ options that take either a method name or an array of method names:
+Layouts specified at the controller level support +:only+ and +:except+ options that take either a method name or an array of method names which correspond to method names within the controller:
<ruby>
class ProductsController < ApplicationController
layout "product", :except => [:index, :rss]
- #...
end
</ruby>
@@ -343,7 +438,6 @@ Layouts are shared downwards in the hierarchy, and more specific layouts always
<ruby>
class ApplicationController < ActionController::Base
layout "main"
- #...
end
</ruby>
@@ -351,7 +445,6 @@ end
<ruby>
class PostsController < ApplicationController
- # ...
end
</ruby>
@@ -360,7 +453,6 @@ end
<ruby>
class SpecialPostsController < PostsController
layout "special"
- # ...
end
</ruby>
@@ -418,6 +510,8 @@ def show
end
</ruby>
+Make sure you use +and return+ and not +&& return+ because while the former will work, the latter will not due to operator precedence in the Ruby Language.
+
Note that the implicit render done by ActionController detects if +render+ has been called, and thus avoids this error. Therefore, the following will work without errors:
<ruby>
@@ -463,11 +557,11 @@ Consider these actions to see the difference:
<ruby>
def index
- @books = Book.find(:all)
+ @books = Book.all
end
def show
- @book = Book.find(params[:id])
+ @book = Book.find_by_id(params[:id])
if @book.nil?
render :action => "index"
end
@@ -478,19 +572,39 @@ With the code in this form, there will be likely be a problem if the +@book+ var
<ruby>
def index
- @books = Book.find(:all)
+ @books = Book.all
end
def show
- @book = Book.find(params[:id])
+ @book = Book.find_by_id(params[:id])
if @book.nil?
- redirect_to :action => "index"
+ redirect_to :action => :index
end
end
</ruby>
With this code, the browser will make a fresh request for the index page, the code in the +index+ method will run, and all will be well.
+The only downside to this code, is that it requires a round trip to the browser, the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 301 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen.
+
+While in a small app, this added latency might not be a problem, it is something to think about when speed of response is of the essence. One way to handle this double request (though a contrived example) could be:
+
+<ruby>
+def index
+ @books = Book.all
+end
+
+def show
+ @book = Book.find_by_id(params[:id])
+ if @book.nil?
+ @books = Book.all
+ render "index", :alert => 'Your book was not found!'
+ end
+end
+</ruby>
+
+Which would detect that there are no books populate the +@books+ instance variable with all the books in the database and then directly render the +index.html.erb+ template returning it to the browser with a flash alert message telling the user what happened.
+
h4. Using +head+ To Build Header-Only Responses
The +head+ method exists to let you send back responses to the browser that have only headers. It provides a more obvious alternative to calling +render :nothing+. The +head+ method takes one response, which is interpreted as a hash of header names and values. For example, you can return only an error header:
@@ -499,12 +613,39 @@ The +head+ method exists to let you send back responses to the browser that have
head :bad_request
</ruby>
+Which would produce the following header:
+
+<shell>
+HTTP/1.1 400 Bad Request
+Connection: close
+Date: Sun, 24 Jan 2010 12:15:53 GMT
+Transfer-Encoding: chunked
+Content-Type: text/html; charset=utf-8
+X-Runtime: 0.013483
+Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
+Cache-Control: no-cache
+</shell>
+
Or you can use other HTTP headers to convey additional information:
<ruby>
head :created, :location => photo_path(@photo)
</ruby>
+Which would produce:
+
+<shell>
+HTTP/1.1 201 Created
+Connection: close
+Date: Sun, 24 Jan 2010 12:16:44 GMT
+Transfer-Encoding: chunked
+Location: /photos/1
+Content-Type: text/html; charset=utf-8
+X-Runtime: 0.083496
+Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
+Cache-Control: no-cache
+</shell>
+
h3. Structuring Layouts
When Rails renders a view as a response, it does so by combining the view with the current layout (using the rules for finding the current layout that were covered earlier in this guide). Within a layout, you have access to three tools for combining different bits of output to form the overall response:
@@ -517,12 +658,14 @@ I'll discuss each of these in turn.
h4. Asset Tags
-Asset tags provide methods for generating HTML that links views to assets like images, javascript, stylesheets, and feeds. There are four types of include tag:
+Asset tags provide methods for generating HTML that links views to assets like images, videos, audio, javascript, stylesheets, and feeds. There are six types of include tag:
* +auto_discovery_link_tag+
* +javascript_include_tag+
* +stylesheet_link_tag+
* +image_tag+
+* +video_tag+
+* +audio_tag+
You can use these tags in layouts or other views, although the tags other than +image_tag+ are most commonly used in the +&lt;head&gt;+ section of a layout.
@@ -663,10 +806,10 @@ You can even use dynamic paths such as +cache/#{current_site}/main/display+.
h5. Linking to Images with +image_tag+
-The +image_tag+ helper builds an HTML +&lt;image&gt;+ tag to the specified file. By default, files are loaded from +public/images+. If you don't specify an extension, +.png+ is assumed by default:
+The +image_tag+ helper builds an HTML +&lt;image /&gt;+ tag to the specified file. By default, files are loaded from +public/images+, note, you must specify the extension, previous versions of Rails would allow you to just call the image name and would append +.png+ if no extension was given, Rails 3.0 does not.
<erb>
-<%= image_tag "header" %>
+<%= image_tag "header.png" %>
</erb>
You can supply a path to the image if you like:
@@ -678,14 +821,93 @@ You can supply a path to the image if you like:
You can supply a hash of additional HTML options:
<erb>
-<%= image_tag "icons/delete.gif", :height => 45 %>
+<%= image_tag "icons/delete.gif", {:height => 45} %>
+</erb>
+
+You can also supply an alternate image to show on mouseover:
+
+<erb>
+<%= image_tag "home.gif", :onmouseover => "menu/home_highlight.gif" %>
+</erb>
+
+Or alternate text if the user has rendering images turned off in their browser, if you do not specify an explicit alt tag, it defaults to the file name of the file, capitalized and with no extension, for example, these two image tags would return the same code:
+
+<erb>
+<%= image_tag "home.gif" %>
+<%= image_tag "home.gif", :alt => "Home" %>
+</erb>
+
+You can also specify a special size tag, in the format "{width}x{height}":
+
+<erb>
+<%= image_tag "home.gif", :size => "50x20" %>
+</erb>
+
+In addition to the above special tags, you can supply a final hash of standard HTML options, such as +:class+ or +:id+ or +:name+:
+
+<erb>
+<%= image_tag "home.gif", :alt => "Go Home",
+ :id => "HomeImage",
+ :class => 'nav_bar' %>
+</erb>
+
+h5. Linking to Videos with +video_tag+
+
+The +video_tag+ helper builds an HTML 5 +&lt;video&gt;+ tag to the specified file. By default, files are loaded from +public/videos+.
+
+<erb>
+<%= video_tag "movie.ogg" %>
+</erb>
+
+Produces
+
+<erb>
+<video src="/videos/movie.ogg" />
</erb>
-There are also three special options you can use with +image_tag+:
+Like an +image_tag+ you can supply a path, either absolute, or relative to the +public/videos+ directory. Additionally you can specify the +:size => "#{width}x#{height}"+ option just like an +image_tag+. Video tags can also have any of the HTML options specified at the end (+id+, +class+ et al).
-* +:alt+ specifies the alt text for the image (which defaults to the file name of the file, capitalized and with no extension)
-* +:size+ specifies both width and height, in the format "{width}x{height}" (for example, "150x125")
-* +:mouseover+ sets an alternate image to be used when the onmouseover event is fired.
+The video tag also supports all of the +&lt;video&gt;+ HTML options through the HTML options hash, including:
+
+* +:poster => 'image_name.png'+, provides an image to put in place of the video before it starts playing.
+* +:autoplay => true+, starts playing the video on page load.
+* +:loop => true+, loops the video once it gets to the end.
+* +:controls => true+, provides browser supplied controls for the user to interact with the video.
+* +:autobuffer => true+, the video will pre load the file for the user on page load.
+
+You can also specify multiple videos to play by passing an array of videos to the +video_tag+:
+
+<erb>
+<%= video_tag ["trailer.ogg", "movie.ogg"] %>
+</erb>
+
+This will produce:
+
+<erb>
+<video><source src="trailer.ogg" /><source src="movie.ogg" /></video>
+</erb>
+
+h5. Linking to Audio files with +audio_tag+
+
+The +audio_tag+ helper builds an HTML 5 +&lt;audio&gt;+ tag to the specified file. By default, files are loaded from +public/audios+.
+
+<erb>
+<%= audio_tag "music.mp3" %>
+</erb>
+
+You can supply a path to the image if you like:
+
+<erb>
+<%= image_tag "music/first_song.mp3" %>
+</erb>
+
+You can also supply a hash of additional options, such as +:id+, +:class+ etc.
+
+Like the +video_tag+, the +audio_tag+ has special options:
+
+* +:autoplay => true+, starts playing the audio on page load
+* +:controls => true+, provides browser supplied controls for the user to interact with the audio.
+* +:autobuffer => true+, the audio will pre load the file for the user on page load.
h4. Understanding +yield+
@@ -752,13 +974,13 @@ h5. Naming Partials
To render a partial as part of a view, you use the +render+ method within the view, and include the +:partial+ option:
<ruby>
-<%= render :partial => "menu" %>
+<%= render "menu" %>
</ruby>
This will render a file named +_menu.html.erb+ at that point within the view being rendered. Note the leading underscore character: partials are named with a leading underscore to distinguish them from regular views, even though they are referred to without the underscore. This holds true even when you're pulling in a partial from another folder:
<ruby>
-<%= render :partial => "shared/menu" %>
+<%= render "shared/menu" %>
</ruby>
That code will pull in the partial from +app/views/shared/_menu.html.erb+.
@@ -768,14 +990,14 @@ h5. Using Partials to Simplify Views
One way to use partials is to treat them as the equivalent of subroutines: as a way to move details out of a view so that you can grasp what's going on more easily. For example, you might have a view that looked like this:
<erb>
-<%= render :partial => "shared/ad_banner" %>
+<%= render "shared/ad_banner" %>
<h1>Products</h1>
<p>Here are a few of our fine products:</p>
...
-<%= render :partial => "shared/footer" %>
+<%= render "shared/footer" %>
</erb>
Here, the +_ad_banner.html.erb+ and +_footer.html.erb+ partials could contain content that is shared among many pages in your application. You don't need to see the details of these sections when you're concentrating on a particular page.
@@ -787,7 +1009,7 @@ h5. Partial Layouts
A partial can use its own layout file, just as a view can use a layout. For example, you might call a partial like this:
<erb>
-<%= render :partial => "link_area", :layout => "graybar" %>
+<%= render "link_area", :layout => "graybar" %>
</erb>
This would look for a partial named +_link_area.html.erb+ and render it using the layout +_graybar.html.erb+. Note that layouts for partials follow the same leading-underscore naming as regular partials, and are placed in the same folder with the partial that they belong to (not in the master +layouts+ folder).
@@ -801,8 +1023,7 @@ You can also pass local variables into partials, making them even more powerful
<erb>
<h1>New zone</h1>
<%= error_messages_for :zone %>
-<%= render :partial => "form", :locals =>
- { :button_label => "Create zone", :zone => @zone } %>
+<%= render :partial => "form", :locals => { :zone => @zone } %>
</erb>
* +edit.html.erb+
@@ -810,8 +1031,7 @@ You can also pass local variables into partials, making them even more powerful
<erb>
<h1>Editing zone</h1>
<%= error_messages_for :zone %>
-<%= render :partial => "form", :locals =>
- { :button_label => "Update zone", :zone => @zone } %>
+<%= render :partial => "form", :locals => { :zone => @zone } %>
</erb>
* +_form.html.erb+
@@ -823,12 +1043,12 @@ You can also pass local variables into partials, making them even more powerful
<%= f.text_field :name %>
</p>
<p>
- <%= f.submit button_label %>
+ <%= f.submit %>
</p>
<% end %>
</erb>
-Although the same partial will be rendered into both views, the label on the submit button is controlled by a local variable passed into the partial.
+Although the same partial will be rendered into both views, Action View's submit helper will return "Create Zone" for the new action and "Update Zone" for the edit action.
Every partial also has a local variable with the same name as the partial (minus the underscore). You can pass an object in to this local variable via the +:object+ option:
@@ -838,15 +1058,15 @@ Every partial also has a local variable with the same name as the partial (minus
Within the +customer+ partial, the +customer+ variable will refer to +@new_customer+ from the parent view.
-WARNING: In previous versions of Rails, the default local variable would look for an instance variable with the same name as the partial in the parent. This behavior is deprecated in Rails 2.2 and will be removed in a future version.
+WARNING: In previous versions of Rails, the default local variable would look for an instance variable with the same name as the partial in the parent. This behavior was deprecated in 2.3 and has been removed in Rails 3.0.
If you have an instance of a model to render into a partial, you can use a shorthand syntax:
<erb>
-<%= render :partial => @customer %>
+<%= render @customer %>
</erb>
-Assuming that the +@customer+ instance variable contains an instance of the +Customer+ model, this will use +_customer.html.erb+ to render it.
+Assuming that the +@customer+ instance variable contains an instance of the +Customer+ model, this will use +_customer.html.erb+ to render it and will pass the local variable +customer+ into the partial which will refer to the +@customer+ instance variable in the parent view.
h5. Rendering Collections
@@ -865,63 +1085,70 @@ Partials are very useful in rendering collections. When you pass a collection to
<p>Product Name: <%= product.name %></p>
</erb>
-When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered. To use a custom local variable name within the partial, specify the +:as+ option in the call to the partial:
+When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered.
+
+In Rails 3.0 there is also a shorthand for this, assuming +@posts+ is a collection of +post+ instances, you can simply do in the +index.html.erb+:
<erb>
-<%= render :partial => "product", :collection => @products, :as => :item %>
+<h1>Products</h1>
+<%= render @products %>
</erb>
-With this change, you can access an instance of the +@products+ collection as the +item+ local variable within the partial.
+To produce the same result.
-TIP: Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by +_counter+. For example, if you're rendering +@products+, within the partial you can refer to +product_counter+ to tell you how many times the partial has been rendered.
+Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way, and Rails will choose the proper partial for each member of the collection:
-You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option:
+* +index.html.erb+
<erb>
-<%= render :partial => "product", :collection => @products,
- :spacer_template => "product_ruler" %>
+<h1>Contacts</h1>
+<%= render [customer1, employee1, customer2, employee2] %>
</erb>
-Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials.
-
-There's also a shorthand syntax available for rendering collections. For example, if +@products+ is a collection of products, you can render the collection this way:
-
-* +index.html.erb+
+* +customers/_customer.html.erb+
<erb>
-<h1>Products</h1>
-<%= render :partial => @products %>
+<p>Customer: <%= customer.name %></p>
</erb>
-* +_product.html.erb+
+* +employees/_employee.html.erb+
<erb>
-<p>Product Name: <%= product.name %></p>
+<p>Employee: <%= employee.name %></p>
</erb>
-Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way, and Rails will choose the proper partial for each member of the collection:
+In this case, Rails will use the customer or employee partials as appropriate for each member of the collection.
-* +index.html.erb+
+h5. Local Variables
+
+To use a custom local variable name within the partial, specify the +:as+ option in the call to the partial:
<erb>
-<h1>Contacts</h1>
-<%= render :partial =>
- [customer1, employee1, customer2, employee2] %>
+<%= render :partial => "product", :collection => @products, :as => :item %>
</erb>
-* +_customer.html.erb+
+With this change, you can access an instance of the +@products+ collection as the +item+ local variable within the partial.
+
+You can also pass in arbitrary local variables to any partial you are rendering with the +:locals => {}+ option:
<erb>
-<p>Name: <%= customer.name %></p>
+<%= render :partial => 'products', :collection => @products,
+ :as => :item, :locals => {:title => "Products Page"} %>
</erb>
-* +_employee.html.erb+
+Would render a partial +_products.html.erb+ once for each instance of +product+ in the +@products+ instance variable passing the instance to the partial as a local variable called +item+ and to each partial, make the local variable +title+ available with the value +Products Page+.
+
+TIP: Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by +_counter+. For example, if you're rendering +@products+, within the partial you can refer to +product_counter+ to tell you how many times the partial has been rendered. This does not work in conjunction with the +:as => :value+ option.
+
+You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option:
+
+h5. Spacer Templates
<erb>
-<p>Name: <%= employee.name %></p>
+<%= render @products, :spacer_template => "product_ruler" %>
</erb>
-In this case, Rails will use the customer or employee partials as appropriate for each member of the collection.
+Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials.
h4. Using Nested Layouts
@@ -964,12 +1191,13 @@ On pages generated by +NewsController+, you want to hide the top menu and add a
That's it. The News views will use the new layout, hiding the top menu and adding a new right menu inside the "content" div.
-There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the +ActionView::render+ method via +render :file => 'layouts/news'+ to base a new layout on the News layout. If one is sure she will not subtemplate the +News+ layout, she can omit the +yield(:news_content) or + part.
+There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the +ActionView::render+ method via +render :file => 'layouts/news'+ to base a new layout on the News layout. If you are sure you will not subtemplate the +News+ layout, you can replace the +yield(:news_content) or yield+ with simply +yield+.
h3. Changelog
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/15
+* January 25, 2010: Rails 3.0 Update by "Mikel Lindsaar":credits.html#raasdnil
* December 27, 2008: Merge patch from Rodrigo Rosenfeld Rosas covering subtemplates
* December 27, 2008: Information on new rendering defaults by "Mike Gunderloy":credits.html#mgunderloy
* November 9, 2008: Added partial collection counter by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile
index 24f0578545..c764597a65 100644
--- a/railties/guides/source/routing.textile
+++ b/railties/guides/source/routing.textile
@@ -45,7 +45,7 @@ There are two components to routing in Rails: the routing engine itself, which i
h4. Processing the File
-In format, +routes.rb+ is nothing more than one big block sent to +ActionController::Routing::Routes.draw+. Within this block, you can have comments, but it's likely that most of your content will be individual lines of code - each line being a route in your application. You'll find five main types of content in this file:
+In format, +routes.rb+ is nothing more than one big block sent to +ApplicationName::Application.routes.draw+. Within this block, you can have comments, but it's likely that most of your content will be individual lines of code - each line being a route in your application. You'll find five main types of content in this file:
* RESTful Routes
* Named Routes
@@ -62,7 +62,7 @@ h4. RESTful Routes
RESTful routes take advantage of the built-in REST orientation of Rails to wrap up a lot of routing information in a single declaration. A RESTful route looks like this:
<ruby>
-map.resources :books
+resources :books
</ruby>
h4. Named Routes
@@ -70,16 +70,24 @@ h4. Named Routes
Named routes give you very readable links in your code, as well as handling incoming requests. Here's a typical named route:
<ruby>
+match 'login' => 'sessions#new', :as => 'login'
+</ruby>
+
+If you're coming from Rails 2, this route will be equivalent to:
+
+<ruby>
map.login '/login', :controller => 'sessions', :action => 'new'
</ruby>
+You will also notice that +sessions#new+ is a shorthand for +:controller => 'sessions', :action => 'new'+
+
h4. Nested Routes
Nested routes let you declare that one resource is contained within another resource. You'll see later on how this translates to URLs and paths in your code. For example, if your application includes parts, each of which belongs to an assembly, you might have this nested route declaration:
<ruby>
-map.resources :assemblies do |assemblies|
- assemblies.resources :parts
+resources :assemblies do
+ resources :parts
end
</ruby>
@@ -88,7 +96,7 @@ h4. Regular Routes
In many applications, you'll also see non-RESTful routing, which explicitly connects the parts of a URL to a particular action. For example,
<ruby>
-map.connect 'parts/:number', :controller => 'inventory', :action => 'show'
+match 'parts/:number' => 'inventory#show'
</ruby>
h4. Default Routes
@@ -96,8 +104,7 @@ h4. Default Routes
The default routes are a safety net that catch otherwise-unrouted requests. Many Rails applications will contain this pair of default routes:
<ruby>
-map.connect ':controller/:action/:id'
-map.connect ':controller/:action/:id.:format'
+match ':controller(/:action(/:id(.:format)))'
</ruby>
These default routes are automatically generated when you create a new Rails application. If you're using RESTful routing for everything in your application, you will probably want to remove them. But be sure you're not using the default routes before you remove them!
@@ -126,7 +133,7 @@ h4. CRUD, Verbs, and Actions
In Rails, a RESTful route provides a mapping between HTTP verbs, controller actions, and (implicitly) CRUD operations in a database. A single entry in the routing file, such as
<ruby>
-map.resources :photos
+resources :photos
</ruby>
creates seven different routes in your application:
@@ -164,26 +171,26 @@ photos_path # => "/photos"
h4. Defining Multiple Resources at the Same Time
-If you need to create routes for more than one RESTful resource, you can save a bit of typing by defining them all with a single call to +map.resources+:
+If you need to create routes for more than one RESTful resource, you can save a bit of typing by defining them all with a single call to +resources+:
<ruby>
-map.resources :photos, :books, :videos
+resources :photos, :books, :videos
</ruby>
This has exactly the same effect as
<ruby>
-map.resources :photos
-map.resources :books
-map.resources :videos
+resources :photos
+resources :books
+resources :videos
</ruby>
h4. Singular Resources
-You can also apply RESTful routing to singleton resources within your application. In this case, you use +map.resource+ instead of +map.resources+ and the route generation is slightly different. For example, a routing entry of
+You can also apply RESTful routing to singleton resources within your application. In this case, you use +resource+ instead of +resources+ and the route generation is slightly different. For example, a routing entry of
<ruby>
-map.resource :geocoder
+resource :geocoder
</ruby>
creates six different routes in your application:
@@ -226,7 +233,7 @@ h5. Using +:controller+
The +:controller+ option lets you use a controller name that is different from the public-facing resource name. For example, this routing entry:
<ruby>
-map.resources :photos, :controller => "images"
+resources :photos, :controller => "images"
</ruby>
will recognize incoming URLs containing +photo+ but route the requests to the Images controller:
@@ -247,7 +254,7 @@ h4. Controller Namespaces and Routing
Rails allows you to group your controllers into namespaces by saving them in folders underneath +app/controllers+. The +:controller+ option provides a convenient way to use these routes. For example, you might have a resource whose controller is purely for admin users in the +admin+ folder:
<ruby>
-map.resources :adminphotos, :controller => "admin/photos"
+resources :adminphotos, :controller => "admin/photos"
</ruby>
If you use controller namespaces, you need to be aware of a subtlety in the Rails routing code: it always tries to preserve as much of the namespace from the previous request as possible. For example, if you are on a view generated from the +adminphoto_path+ helper, and you follow a link generated with +&lt;%= link_to "show", adminphoto(1) %&gt;+ you will end up on the view generated by +admin/photos/show+, but you will also end up in the same place if you have +&lt;%= link_to "show", {:controller => "photos", :action => "show"} %&gt;+ because Rails will generate the show URL relative to the current URL.
@@ -257,13 +264,13 @@ TIP: If you want to guarantee that a link goes to a top-level controller, use a
You can also specify a controller namespace with the +:namespace+ option instead of a path:
<ruby>
-map.resources :adminphotos, :namespace => "admin", :controller => "photos"
+resources :adminphotos, :namespace => "admin", :controller => "photos"
</ruby>
-This can be especially useful when combined with +with_options+ to map multiple namespaced routes together:
+This can be especially useful when map multiple namespaced routes together using +namespace+ block by:
<ruby>
-map.with_options(:namespace => "admin") do |admin|
+namespace :admin do
admin.resources :photos, :videos
end
</ruby>
@@ -275,7 +282,7 @@ h5. Using +:singular+
If for some reason Rails isn't doing what you want in converting the plural resource name to a singular name in member routes, you can override its judgment with the +:singular+ option:
<ruby>
-map.resources :teeth, :singular => "tooth"
+resources :teeth, :singular => "tooth"
</ruby>
TIP: Depending on the other code in your application, you may prefer to add additional rules to the +Inflector+ class instead.
@@ -285,7 +292,7 @@ h5. Using +:requirements+
You can use the +:requirements+ option in a RESTful route to impose a format on the implied +:id+ parameter in the singular routes. For example:
<ruby>
-map.resources :photos, :requirements => {:id => /[A-Z][A-Z][0-9]+/}
+resources :photos, :requirements => {:id => /[A-Z][A-Z][0-9]+/}
</ruby>
This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, +/photos/1+ would no longer be recognized by this route, but +/photos/RR27+ would.
@@ -299,7 +306,7 @@ h5. Using +:as+
The +:as+ option lets you override the normal naming for the actual generated paths. For example:
<ruby>
-map.resources :photos, :as => "images"
+resources :photos, :as => "images"
</ruby>
will recognize incoming URLs containing +image+ but route the requests to the Photos controller:
@@ -320,7 +327,7 @@ h5. Using +:path_names+
The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in URLs:
<ruby>
-map.resources :photos, :path_names => { :new => 'make', :edit => 'change' }
+resources :photos, :path_names => { :new => 'make', :edit => 'change' }
</ruby>
This would cause the routing to recognize URLs such as
@@ -343,7 +350,7 @@ h5. Using +:path_prefix+
The +:path_prefix+ option lets you add additional parameters that will be prefixed to the recognized paths. For example, suppose each photo in your application belongs to a particular photographer. In that case, you might declare this route:
<ruby>
-map.resources :photos, :path_prefix => '/photographers/:photographer_id'
+resources :photos, :path_prefix => '/photographers/:photographer_id'
</ruby>
Routes recognized by this entry would include:
@@ -362,9 +369,9 @@ h5. Using +:name_prefix+
You can use the :name_prefix option to avoid collisions between routes. This is most useful when you have two resources with the same name that use +:path_prefix+ to map differently. For example:
<ruby>
-map.resources :photos, :path_prefix => '/photographers/:photographer_id',
+resources :photos, :path_prefix => '/photographers/:photographer_id',
:name_prefix => 'photographer_'
-map.resources :photos, :path_prefix => '/agencies/:agency_id',
+resources :photos, :path_prefix => '/agencies/:agency_id',
:name_prefix => 'agency_'
</ruby>
@@ -377,7 +384,7 @@ h5. Using +:only+ and +:except+
By default, Rails creates routes for all seven of the default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the +:only+ and +:except+ options to fine-tune this behavior. The +:only+ option specifies that only certain routes should be generated:
<ruby>
-map.resources :photos, :only => [:index, :show]
+resources :photos, :only => [:index, :show]
</ruby>
With this declaration, a +GET+ request to +/photos+ would succeed, but a +POST+ request to +/photos+ (which would ordinarily be routed to the create action) will fail.
@@ -385,7 +392,7 @@ With this declaration, a +GET+ request to +/photos+ would succeed, but a +POST+
The +:except+ option specifies a route or list of routes that should _not_ be generated:
<ruby>
-map.resources :photos, :except => :destroy
+resources :photos, :except => :destroy
</ruby>
In this case, all of the normal routes except the route for +destroy+ (a +DELETE+ request to +/photos/<em>id</em>+) will be generated.
@@ -411,12 +418,12 @@ end
Each ad is logically subservient to one magazine. Nested routes allow you to capture this relationship in your routing. In this case, you might include this route declaration:
<ruby>
-map.resources :magazines do |magazine|
- magazine.resources :ads
+resources :magazines do
+ resources :ads
end
</ruby>
-TIP: Further below you'll learn about a convenient shortcut for this construct:<br/>+map.resources :magazines, :has_many => :ads+
+TIP: Further below you'll learn about a convenient shortcut for this construct:<br/>+resources :magazines, :has_many => :ads+
In addition to the routes for magazines, this declaration will also create routes for ads, each of which requires the specification of a magazine in the URL:
@@ -437,16 +444,16 @@ h5. Using +:name_prefix+
The +:name_prefix+ option overrides the automatically-generated prefix in nested route helpers. For example,
<ruby>
-map.resources :magazines do |magazine|
- magazine.resources :ads, :name_prefix => 'periodical'
+resources :magazines do
+ resources :ads, :name_prefix => 'periodical'
end
</ruby>
This will create routing helpers such as +periodical_ads_url+ and +periodical_edit_ad_path+. You can even use +:name_prefix+ to suppress the prefix entirely:
<ruby>
-map.resources :magazines do |magazine|
- magazine.resources :ads, :name_prefix => nil
+resources :magazines do
+ resources :ads, :name_prefix => nil
end
</ruby>
@@ -462,16 +469,16 @@ h5. Using +:has_one+ and +:has_many+
The +:has_one+ and +:has_many+ options provide a succinct notation for simple nested routes. Use +:has_one+ to nest a singleton resource, or +:has_many+ to nest a plural resource:
<ruby>
-map.resources :photos, :has_one => :photographer, :has_many => [:publications, :versions]
+resources :photos, :has_one => :photographer, :has_many => [:publications, :versions]
</ruby>
This has the same effect as this set of declarations:
<ruby>
-map.resources :photos do |photo|
- photo.resource :photographer
- photo.resources :publications
- photo.resources :versions
+resources :photos do
+ resource :photographer
+ resources :publications
+ resources :versions
end
</ruby>
@@ -480,9 +487,9 @@ h5. Limits to Nesting
You can nest resources within other nested resources if you like. For example:
<ruby>
-map.resources :publishers do |publisher|
- publisher.resources :magazines do |magazine|
- magazine.resources :photos
+resources :publishers do
+ resources :magazines do
+ resources :photos
end
end
</ruby>
@@ -502,9 +509,9 @@ h5. Shallow Nesting
The +:shallow+ option provides an elegant solution to the difficulties of deeply-nested routes. If you specify this option at any level of routing, then paths for nested resources which reference a specific member (that is, those with an +:id+ parameter) will not use the parent path prefix or name prefix. To see what this means, consider this set of routes:
<ruby>
-map.resources :publishers, :shallow => true do |publisher|
- publisher.resources :magazines do |magazine|
- magazine.resources :photos
+resources :publishers, :shallow => true do
+ resources :magazines do
+ resources :photos
end
end
</ruby>
@@ -522,7 +529,7 @@ This will enable recognition of (among others) these routes:
With shallow nesting, you need only supply enough information to uniquely identify the resource that you want to work with. If you like, you can combine shallow nesting with the +:has_one+ and +:has_many+ options:
<ruby>
-map.resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
+resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
</ruby>
h4. Route Generation from Arrays
@@ -530,8 +537,8 @@ h4. Route Generation from Arrays
In addition to using the generated routing helpers, Rails can also generate RESTful routes from an array of parameters. For example, suppose you have a set of routes generated with these entries in routes.rb:
<ruby>
-map.resources :magazines do |magazine|
- magazine.resources :ads
+resources :magazines do
+ resources :ads
end
</ruby>
@@ -554,17 +561,16 @@ h4. Namespaced Resources
It's possible to do some quite complex things by combining +:path_prefix+ and +:name_prefix+. For example, you can use the combination of these two options to move administrative resources to their own folder in your application:
<ruby>
-map.resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
-map.resources :tags, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
-map.resources :ratings, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
+resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
+resources :tags, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
+resources :ratings, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
</ruby>
The good news is that if you find yourself using this level of complexity, you can stop. Rails supports _namespaced resources_ to make placing resources in their own folder a snap. Here's the namespaced version of those same three routes:
<ruby>
-map.namespace(:admin) do |admin|
- admin.resources :photos,
- :has_many => { :tags, :ratings}
+namespace :admin do
+ resources :photos, :has_many => { :tags, :ratings }
end
</ruby>
@@ -576,18 +582,24 @@ You are not limited to the seven routes that RESTful routing creates by default.
h5. Adding Member Routes
-To add a member route, use the +:member+ option:
+To add a member route, just add +member+ block into resource block:
<ruby>
-map.resources :photos, :member => { :preview => :get }
+resources :photos do
+ member do
+ get :preview
+ end
+end
</ruby>
This will enable Rails to recognize URLs such as +/photos/1/preview+ using the GET HTTP verb, and route them to the preview action of the Photos controller. It will also create the +preview_photo_url+ and +preview_photo_path+ route helpers.
-Within the hash of member routes, each route name specifies the HTTP verb that it will recognize. You can use +:get+, +:put+, +:post+, +:delete+, or +:any+ here. You can also specify an array of methods, if you need more than one but you don't want to allow just anything:
+Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, +delete+, or +any+ here. If you don't have multiple +member+ route, you can also passing +:on+ to the routing.
<ruby>
-map.resources :photos, :member => { :prepare => [:get, :post] }
+resources :photos do
+ get :preview, :on => :member
+end
</ruby>
h5. Adding Collection Routes
@@ -595,32 +607,35 @@ h5. Adding Collection Routes
To add a collection route, use the +:collection+ option:
<ruby>
-map.resources :photos, :collection => { :search => :get }
+resources :photos do
+ collection do
+ get :search
+ end
+end
</ruby>
This will enable Rails to recognize URLs such as +/photos/search+ using the GET HTTP verb, and route them to the search action of the Photos controller. It will also create the +search_photos_url+ and +search_photos_path+ route helpers.
-Just as with member routes, you can specify an array of methods for a collection route:
+Just as with member routes, you can passing +:on+ to the routing.
<ruby>
-map.resources :photos, :collection => { :search => [:get, :post] }
+resources :photos do
+ get :search, :on => :collection
+end
</ruby>
h5. Adding New Routes
-To add a new route (one that creates a new resource), use the +:new+ option:
+As of writing, Rails 3 has deprecated +:new+ option from routing. You will need to explicit define the route using +match+ method
<ruby>
-map.resources :photos, :new => { :upload => :post }
+resources :photos
+match 'photos/new/upload' => 'photos#upload', :as => 'upload_new_photos'
</ruby>
-This will enable Rails to recognize URLs such as +/photos/new/upload+ using the POST HTTP verb, and route them to the upload action of the Photos controller. It will also create the +upload_new_photos_path+ and +upload_new_photos_url+ route helpers.
-
-TIP: If you want to redefine the verbs accepted by one of the standard actions, you can do so by explicitly mapping that action. For example:<br/>+map.resources :photos, :new => { :new => :any }+<br/>This will allow the new action to be invoked by any request to +photos/new+, no matter what HTTP verb you use.
-
h5. A Note of Caution
-If you find yourself adding many extra actions to a RESTful route, it's time to stop and ask yourself whether you're disguising the presence of another resource that would be better split off on its own. When the +:member+ and +:collection+ hashes become a dumping-ground, RESTful routes lose the advantage of easy readability that is one of their strongest points.
+If you find yourself adding many extra actions to a RESTful route, it's time to stop and ask yourself whether you're disguising the presence of another resource that would be better split off on its own. When the +member+ and +collection+ hashes become a dumping-ground, RESTful routes lose the advantage of easy readability that is one of their strongest points.
h3. Regular Routes
@@ -633,7 +648,7 @@ h4. Bound Parameters
When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: +:controller+ maps to the name of a controller in your application, and +:action+ maps to the name of an action within that controller. For example, consider one of the default Rails routes:
<ruby>
-map.connect ':controller/:action/:id'
+match ':controller(/:action(/:id))'
</ruby>
If an incoming request of +/photos/show/1+ is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the +show+ action of the +Photos+ controller, and to make the final parameter (1) available as +params[:id]+.
@@ -643,7 +658,7 @@ h4. Wildcard Components
You can set up as many wildcard symbols within a regular route as you like. Anything other than +:controller+ or +:action+ will be available to the matching action as part of the params hash. So, if you set up this route:
<ruby>
-map.connect ':controller/:action/:id/:user_id'
+match ':controller/:action/:id/:user_id'
</ruby>
An incoming URL of +/photos/show/1/2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be set to 2.
@@ -653,7 +668,7 @@ h4. Static Text
You can specify static text when creating a route. In this case, the static text is used only for matching the incoming requests:
<ruby>
-map.connect ':controller/:action/:id/with_user/:user_id'
+match ':controller/:action/:id/with_user/:user_id'
</ruby>
This route would respond to URLs such as +/photos/show/1/with_user/2+.
@@ -663,17 +678,17 @@ h4. Querystring Parameters
Rails routing automatically picks up querystring parameters and makes them available in the +params+ hash. For example, with this route:
<ruby>
-map.connect ':controller/:action/:id'
+match ':controller/:action/:id
</ruby>
An incoming URL of +/photos/show/1?user_id=2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be equal to 2.
h4. Defining Defaults
-You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply defaults for these two parameters in a hash:
+You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply defaults for these two parameters by putting it after +=>+:
<ruby>
-map.connect 'photos/:id', :controller => 'photos', :action => 'show'
+match 'photos/:id' => 'photos#show'
</ruby>
With this route, an incoming URL of +/photos/12+ would be dispatched to the +show+ action within the +Photos+ controller.
@@ -681,8 +696,7 @@ With this route, an incoming URL of +/photos/12+ would be dispatched to the +sho
You can also define other defaults in a route by supplying a hash for the +:defaults+ option. This even applies to parameters that are not explicitly defined elsewhere in the route. For example:
<ruby>
-map.connect 'photos/:id', :controller => 'photos', :action => 'show',
- :defaults => { :format => 'jpg' }
+match 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' }
</ruby>
With this route, an incoming URL of +photos/12+ would be dispatched to the +show+ action within the +Photos+ controller, and +params[:format]+ will be set to +jpg+.
@@ -692,7 +706,7 @@ h4. Named Routes
Regular routes need not use the +connect+ method. You can use any other name here to create a _named route_. For example,
<ruby>
-map.logout '/logout', :controller => 'sessions', :action => 'destroy'
+match 'logout' => 'sessions#destroy', :as => :logout
</ruby>
This will do two things. First, requests to +/logout+ will be sent to the +destroy+ action of the +Sessions+ controller. Second, Rails will maintain the +logout_path+ and +logout_url+ helpers for use within your code.
@@ -702,15 +716,13 @@ h4. Route Requirements
You can use the +:requirements+ option to enforce a format for any parameter in a route:
<ruby>
-map.connect 'photo/:id', :controller => 'photos', :action => 'show',
- :requirements => { :id => /[A-Z]\d{5}/ }
+match 'photo/:id' => 'photos#show', :requirements => { :id => /[A-Z]\d{5}/ }
</ruby>
This route would respond to URLs such as +/photo/A12345+. You can more succinctly express the same route this way:
<ruby>
-map.connect 'photo/:id', :controller => 'photos', :action => 'show',
- :id => /[A-Z]\d{5}/
+match 'photo/:id' => 'photos#show', :id => /[A-Z]\d{5}/
</ruby>
h4. Route Conditions
@@ -718,8 +730,7 @@ h4. Route Conditions
Route conditions (introduced with the +:conditions+ option) are designed to implement restrictions on routes. Currently, the only supported restriction is +:method+:
<ruby>
-map.connect 'photo/:id', :controller => 'photos', :action => 'show',
- :conditions => { :method => :get }
+match 'photo/:id' => 'photos#show', :conditions => { :method => :get }
</ruby>
As with conditions in RESTful routes, you can specify +:get+, +:post+, +:put+, +:delete+, or +:any+ for the acceptable method.
@@ -729,7 +740,7 @@ h4. Route Globbing
Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example
<ruby>
-map.connect 'photo/*other', :controller => 'photos', :action => 'unknown',
+match 'photo/*other' => 'photos#unknown'
</ruby>
This route would match +photo/12+ or +/photo/long/path/to/12+ equally well, creating an array of path segments as the value of +params[:other]+.
@@ -755,7 +766,7 @@ There's one more way in which routing can do different things depending on diffe
For instance, consider the second of the default routes in the boilerplate +routes.rb+ file:
<ruby>
-map.connect ':controller/:action/:id.:format'
+match ':controller(/:action(/:id(.:format)))'
</ruby>
This route matches requests such as +/photo/edit/1.xml+ or +/photo/show/2.rss+. Within the appropriate action code, you can issue different responses depending on the requested format:
@@ -781,11 +792,10 @@ Mime::Type.register "image/jpg", :jpg
h3. The Default Routes
-When you create a new Rails application, +routes.rb+ is initialized with two default routes:
+When you create a new Rails application, +routes.rb+ is initialized with a default route:
<ruby>
-map.connect ':controller/:action/:id'
-map.connect ':controller/:action/:id.:format'
+match ':controller(/:action(/:id(.:format)))'
</ruby>
These routes provide reasonable defaults for many URLs, if you're not using RESTful routing.
@@ -796,31 +806,24 @@ h3. The Empty Route
Don't confuse the default routes with the empty route. The empty route has one specific purpose: to route requests that come in to the root of the web site. For example, if your site is example.com, then requests to +http://example.com+ or +http://example.com/+ will be handled by the empty route.
-h4. Using +map.root+
+h4. Using +root+
-The preferred way to set up the empty route is with the +map.root+ command:
+The preferred way to set up the empty route is with the +root+ command:
<ruby>
-map.root :controller => "pages", :action => "main"
+root :to => 'pages#main'
</ruby>
The use of the +root+ method tells Rails that this route applies to requests for the root of the site.
-For better readability, you can specify an already-created route in your call to +map.root+:
-
-<ruby>
-map.index 'index', :controller => "pages", :action => "main"
-map.root :index
-</ruby>
-
-Because of the top-down processing of the file, the named route must be specified _before_ the call to +map.root+.
+Because of the top-down processing of the file, the named route must be specified _before_ the call to +root+.
h4. Connecting the Empty String
You can also specify an empty route by explicitly connecting the empty string:
<ruby>
-map.connect '', :controller => "pages", :action => "main"
+match '' => 'pages#main'
</ruby>
TIP: If the empty route does not seem to be working in your application, make sure that you have deleted the file +public/index.html+ from your Rails tree.
@@ -898,6 +901,7 @@ h3. Changelog
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/3
+* Febuary 1, 2010: Modifies the routing documentation to match new routing DSL in Rails 3, by Prem Sichanugrist
* October 4, 2008: Added additional detail on specifying verbs for resource member/collection routes, by "Mike Gunderloy":credits.html#mgunderloy
* September 23, 2008: Added section on namespaced controllers and routing, by "Mike Gunderloy":credits.html#mgunderloy
* September 10, 2008: initial version by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index c038d0ac70..2dc2ba1002 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -2,6 +2,114 @@ require 'rails/initializable'
require 'rails/configuration'
module Rails
+ # Railtie is the core of the Rails Framework and provides all the hooks and
+ # methods you need to link your plugin into Rails.
+ #
+ # What Railtie does is make every component of Rails a "plugin" and creates
+ # an API that exposes all the powers that the builtin components need
+ # to any plugin author.
+ #
+ # In fact, every major component of Rails (Action Mailer, Action Controller,
+ # Action View, Active Record and Active Resource) are all now just plain
+ # old plugins, so anything they can do, your plugin can do.
+ #
+ # Developing a plugin for Rails does not _require_ any implementation of
+ # Railtie, there is no fixed rule, but as a guideline, if your plugin works
+ # by just being required before Rails boots, then there is no need for you
+ # to hook into Railtie, but if you need to interact with the Rails framework
+ # during boot, or after boot, then Railtie is what you need to do that
+ # interaction.
+ #
+ # For example, the following would need you to implement Railtie in your
+ # plugin:
+ #
+ # * creating initializers (including route insertion)
+ # * modifying the render path (think HAML et al)
+ # * adding Rails config.* keys to the environment
+ # * setting up a subscriber to the Rails +ActiveSupport::Notifications+
+ # * adding global Rake tasks into rails
+ # * setting up a default configuration for the Application
+ #
+ # Railtie gives you a central place to connect into the Rails framework. If you
+ # find yourself writing plugin code that is having to monkey patch parts of the
+ # Rails framework to achieve something, there is probably a better, more elegant
+ # way to do it through Railtie, if there isn't, then you have found a lacking
+ # feature of Railtie, please lodge a ticket.
+ #
+ # Implementing Railtie in your plugin is by creating a class Railtie in your
+ # application that has your plugin name and making sure that this gets loaded
+ # durng boot time of the Rails stack.
+ #
+ # You can do this however you wish, but three straight forward ways are:
+ #
+ # == For gems or plugins that are not used outside of Rails
+ #
+ # * Create a Railtie subclass within your lib/my_plugin.rb file:
+ #
+ # # lib/my_plugin.rb
+ # module MyPlugin
+ # class Railtie < Rails::Railtie
+ # end
+ # end
+ #
+ # * Pass in your plugin name
+ #
+ # # lib/my_plugin.rb
+ # module MyPlugin
+ # class Railtie < Rails::Railtie
+ # plugin_name :my_plugin
+ # end
+ # end
+ #
+ # == For gems that could be used without Rails
+ #
+ # * Create a file (say, lib/my_gem/railtie.rb) which contains class Railtie inheriting from
+ # Rails::Railtie and is namespaced to your gem:
+ #
+ # # lib/my_gem/railtie.rb
+ # module MyGem
+ # class Railtie < Rails::Railtie
+ # end
+ # end
+ #
+ # * Require your own gem as well as rails in this file:
+ #
+ # # lib/my_gem/railtie.rb
+ # require 'my_gem'
+ # require 'rails'
+ #
+ # module MyGem
+ # class Railtie < Rails::Railtie
+ # end
+ # end
+ #
+ # * Give your gem a unique name:
+ #
+ # # lib/my_gem/railtie.rb
+ # require 'my_gem'
+ # require 'rails'
+ #
+ # module MyGem
+ # class Railtie < Rails::Railtie
+ # plugin_name :my_gem
+ # end
+ # end
+ #
+ # * Make sure your Gem loads the railtie.rb file if Rails is loaded first, an easy
+ # way to check is by checking for the Rails constant which will exist if Rails
+ # has started:
+ #
+ # # lib/my_gem.rb
+ # module MyGem
+ # require 'lib/railtie' if defined?(Rails)
+ # end
+ #
+ # * Or instead of doing the require automatically, you can ask your users to require
+ # it for you in their Gemfile:
+ #
+ # # #{USER_RAILS_ROOT}/Gemfile
+ # gem "my_gem", :require_as => ["my_gem", "my_gem/railtie"]
+ #
class Railtie
autoload :Configurable, "rails/railtie/configurable"
autoload :Configuration, "rails/railtie/configuration"
diff --git a/railties/lib/rails/subscriber.rb b/railties/lib/rails/subscriber.rb
index 8c62f562d9..6638ff28c1 100644
--- a/railties/lib/rails/subscriber.rb
+++ b/railties/lib/rails/subscriber.rb
@@ -3,10 +3,10 @@ require 'active_support/notifications'
module Rails
# Rails::Subscriber is an object set to consume ActiveSupport::Notifications
- # on initialization with solely purpose of logging. The subscriber dispatches
- # notifications to a regirested object based on its given namespace.
+ # on initialization with the sole purpose of logging. The subscriber dispatches
+ # notifications to a registered object based on it's given namespace.
#
- # An example would be ActiveRecord subscriber responsible for logging queries:
+ # An example would be an Active Record subscriber responsible for logging queries:
#
# module ActiveRecord
# class Railtie
@@ -18,16 +18,16 @@ module Rails
# end
# end
#
- # It's finally registed as:
+ # Which would be registed as:
#
# Rails::Subscriber.add :active_record, ActiveRecord::Railtie::Subscriber.new
#
- # So whenever a "active_record.sql" notification arrive to Rails::Subscriber,
+ # So whenever an +active_record.sql+ notification arrives to Rails::Subscriber,
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
# the sql method.
#
- # This is useful because it avoids spanning several subscribers just for logging
- # purposes(which slows down the main thread). Besides of providing a centralized
+ # This avoids spanning several subscribers just for logging purposes
+ # (which slows down the main thread). It also provides a centralized
# facility on top of Rails.logger.
#
# Subscriber also has some helpers to deal with logging and automatically flushes
@@ -97,7 +97,6 @@ module Rails
# option is set to true, it also adds bold to the string. This is based
# on Highline implementation and it automatically appends CLEAR to the end
# of the returned String.
- #
def color(text, color, bold=false)
return text unless colorize_logging
color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)