Browse files

Merge docrails

  • Loading branch information...
1 parent 6e3bee6 commit dba196cb7f8d34b93f6872e4a43737bb52019065 @lifo lifo committed Jan 17, 2010
Showing with 4,712 additions and 1,198 deletions.
  1. +1 −1 actionmailer/lib/action_mailer/base.rb
  2. +17 −17 actionpack/lib/action_controller/metal/responder.rb
  3. +4 −3 actionpack/lib/action_dispatch/routing.rb
  4. +8 −8 actionpack/lib/action_dispatch/testing/assertions/routing.rb
  5. +3 −0 actionpack/lib/action_view/helpers/form_tag_helper.rb
  6. +1 −1 actionpack/lib/action_view/helpers/sanitize_helper.rb
  7. +2 −4 actionpack/lib/action_view/helpers/text_helper.rb
  8. +52 −16 activemodel/README
  9. +73 −31 activemodel/lib/active_model/callbacks.rb
  10. +12 −1 activemodel/lib/active_model/conversion.rb
  11. +39 −1 activemodel/lib/active_model/dirty.rb
  12. +4 −4 activemodel/lib/active_model/validations/length.rb
  13. +3 −5 activerecord/lib/active_record/associations.rb
  14. +2 −2 activerecord/lib/active_record/base.rb
  15. +1 −2 activerecord/lib/active_record/fixtures.rb
  16. +2 −1 activerecord/lib/active_record/migration.rb
  17. +5 −5 activerecord/lib/active_record/nested_attributes.rb
  18. +7 −0 activeresource/lib/active_resource/base.rb
  19. +1 −1 activesupport/lib/active_support/callbacks.rb
  20. +1 −1 activesupport/lib/active_support/core_ext/array/access.rb
  21. +9 −0 activesupport/lib/active_support/core_ext/array/wrap.rb
  22. +48 −0 activesupport/lib/active_support/core_ext/hash/conversions.rb
  23. +8 −0 activesupport/lib/active_support/core_ext/hash/except.rb
  24. +5 −0 activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
  25. +4 −2 activesupport/lib/active_support/core_ext/hash/keys.rb
  26. +16 −0 activesupport/lib/active_support/core_ext/object/duplicable.rb
  27. +4 −1 activesupport/lib/active_support/core_ext/rexml.rb
  28. +2 −2 activesupport/lib/active_support/core_ext/string/access.rb
  29. +1 −1 activesupport/lib/active_support/multibyte/chars.rb
  30. +53 −9 railties/README
  31. +8 −7 railties/guides/rails_guides.rb
  32. +10 −4 railties/guides/rails_guides/generator.rb
  33. +9 −9 railties/guides/source/2_2_release_notes.textile
  34. +3 −3 railties/guides/source/2_3_release_notes.textile
  35. +1 −3 railties/guides/source/action_mailer_basics.textile
  36. +1,423 −11 railties/guides/source/action_view_overview.textile
  37. +102 −33 railties/guides/source/active_record_basics.textile
  38. +1,835 −0 railties/guides/source/active_support_core_extensions.textile
  39. +0 −818 railties/guides/source/active_support_overview.textile
  40. +41 −0 railties/guides/source/activerecord_validations_callbacks.textile
  41. +285 −37 railties/guides/source/ajax_on_rails.textile
  42. +1 −1 railties/guides/source/association_basics.textile
  43. +4 −0 railties/guides/source/caching_with_rails.textile
  44. +115 −59 railties/guides/source/configuring.textile
  45. +31 −7 railties/guides/source/contributing_to_rails.textile
  46. 0 railties/guides/source/{credits.erb.textile → credits.textile.erb}
  47. +1 −1 railties/guides/source/debugging_rails_applications.textile
  48. +2 −2 railties/guides/source/form_helpers.textile
  49. +378 −0 railties/guides/source/generators.textile
  50. +5 −5 railties/guides/source/getting_started.textile
  51. +1 −1 railties/guides/source/i18n.textile
  52. 0 railties/guides/source/{index.erb.textile → index.textile.erb}
  53. +1 −1 railties/guides/source/migrations.textile
  54. +1 −1 railties/guides/source/plugins.textile
  55. +1 −1 railties/guides/source/rails_on_rack.textile
  56. +3 −3 railties/guides/source/routing.textile
  57. +26 −28 railties/guides/source/security.textile
  58. +37 −44 railties/guides/source/testing.textile
View
2 actionmailer/lib/action_mailer/base.rb
@@ -36,7 +36,7 @@ module ActionMailer #:nodoc:
# * <tt>cc</tt> - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the <tt>Cc:</tt> header.
# * <tt>bcc</tt> - Takes one or more email addresses. These addresses will receive a blind carbon copy of your email. Sets the <tt>Bcc:</tt> header.
# * <tt>reply_to</tt> - Takes one or more email addresses. These addresses will be listed as the default recipients when replying to your email. Sets the <tt>Reply-To:</tt> header.
- # * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header wil be set by the delivery agent.
+ # * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header will be set by the delivery agent.
# * <tt>content_type</tt> - Specify the content type of the message. Defaults to <tt>text/plain</tt>.
# * <tt>headers</tt> - Specify additional headers to be set for the message, e.g. <tt>headers 'X-Mail-Count' => 107370</tt>.
#
View
34 actionpack/lib/action_controller/metal/responder.rb
@@ -1,7 +1,7 @@
module ActionController #:nodoc:
- # Responder is responsible to expose a resource for different mime requests,
+ # Responder is responsible for exposing a resource to different mime requests,
# usually depending on the HTTP verb. The responder is triggered when
- # respond_with is called. The simplest case to study is a GET request:
+ # <code>respond_with</code> is called. The simplest case to study is a GET request:
#
# class PeopleController < ApplicationController
# respond_to :html, :xml, :json
@@ -12,17 +12,17 @@ module ActionController #:nodoc:
# end
# end
#
- # When a request comes, for example with format :xml, three steps happen:
+ # When a request comes in, for example for an XML response, three steps happen:
#
- # 1) responder searches for a template at people/index.xml;
+ # 1) the responder searches for a template at people/index.xml;
#
- # 2) if the template is not available, it will invoke :to_xml in the given resource;
+ # 2) if the template is not available, it will invoke <code>#to_xml</code> on the given resource;
#
- # 3) if the responder does not respond_to :to_xml, call :to_format on it.
+ # 3) if the responder does not <code>respond_to :to_xml</code>, call <code>#to_format</code> on it.
#
# === Builtin HTTP verb semantics
#
- # Rails default responder holds semantics for each HTTP verb. Depending on the
+ # The default Rails responder holds semantics for each HTTP verb. Depending on the
# content type, verb and the resource status, it will behave differently.
#
# Using Rails default responder, a POST request for creating an object could
@@ -55,7 +55,7 @@ module ActionController #:nodoc:
#
# === Nested resources
#
- # You can given nested resource as you do in form_for and polymorphic_url.
+ # You can supply nested resources as you do in <code>form_for</code> and <code>polymorphic_url</code>.
# Consider the project has many tasks example. The create action for
# TasksController would be like:
#
@@ -67,15 +67,15 @@ module ActionController #:nodoc:
# end
#
# Giving an array of resources, you ensure that the responder will redirect to
- # project_task_url instead of task_url.
+ # <code>project_task_url</code> instead of <code>task_url</code>.
#
- # Namespaced and singleton resources requires a symbol to be given, as in
+ # Namespaced and singleton resources require a symbol to be given, as in
# polymorphic urls. If a project has one manager which has many tasks, it
# should be invoked as:
#
# respond_with(@project, :manager, @task)
#
- # Check polymorphic_url documentation for more examples.
+ # Check <code>polymorphic_url</code> documentation for more examples.
#
class Responder
attr_reader :controller, :request, :format, :resource, :resources, :options
@@ -126,7 +126,7 @@ def to_html
navigation_behavior(e)
end
- # All others formats follow the procedure below. First we try to render a
+ # All other formats follow the procedure below. First we try to render a
# template, if the template is not available, we verify if the resource
# responds to :to_format and display it.
#
@@ -183,11 +183,11 @@ def default_render
@default_response.call
end
- # display is just a shortcut to render a resource with the current format.
+ # Display is just a shortcut to render a resource with the current format.
#
# display @user, :status => :ok
#
- # For xml request is equivalent to:
+ # For XML requests it's equivalent to:
#
# render :xml => @user, :status => :ok
#
@@ -204,14 +204,14 @@ def display(resource, given_options={})
controller.render given_options.merge!(options).merge!(format => resource)
end
- # Check if the resource has errors or not.
+ # Check whether the resource has errors.
#
def has_errors?
resource.respond_to?(:errors) && !resource.errors.empty?
end
- # By default, render the :edit action for html requests with failure, unless
- # the verb is post.
+ # By default, render the <code>:edit</code> action for HTML requests with failure, unless
+ # the verb is POST.
#
def default_action
@action ||= ACTIONS_FOR_VERBS[request.method]
View
7 actionpack/lib/action_dispatch/routing.rb
@@ -193,9 +193,10 @@ module ActionDispatch
#
# With conditions you can define restrictions on routes. Currently the only valid condition is <tt>:method</tt>.
#
- # * <tt>:method</tt> - Allows you to specify which method can access the route. Possible values are <tt>:post</tt>,
- # <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>. The default value is <tt>:any</tt>,
- # <tt>:any</tt> means that any method can access the route.
+ # * <tt>:method</tt> - Allows you to specify which HTTP method(s) can access the route. Possible values are
+ # <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>. Use an array to specify more
+ # than one method, e.g. <tt>[ :get, :post ]</tt>. The default value is <tt>:any</tt>, <tt>:any</tt> means that any
+ # method can access the route.
#
# Example:
#
View
16 actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -12,29 +12,29 @@ module RoutingAssertions
# and a :method containing the required HTTP verb.
#
# # assert that POSTing to /items will call the create action on ItemsController
- # assert_recognizes {:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post}
+ # assert_recognizes({:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post})
#
# You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used
# to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the
# extras argument, appending the query string on the path directly will not work. For example:
#
# # assert that a path of '/items/list/1?view=print' returns the correct options
- # assert_recognizes {:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" }
+ # assert_recognizes({:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" })
#
# The +message+ parameter allows you to pass in an error message that is displayed upon failure.
#
# ==== Examples
# # Check the default route (i.e., the index action)
- # assert_recognizes {:controller => 'items', :action => 'index'}, 'items'
+ # assert_recognizes({:controller => 'items', :action => 'index'}, 'items')
#
# # Test a specific action
- # assert_recognizes {:controller => 'items', :action => 'list'}, 'items/list'
+ # assert_recognizes({:controller => 'items', :action => 'list'}, 'items/list')
#
# # Test an action with a parameter
- # assert_recognizes {:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1'
+ # assert_recognizes({:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1')
#
# # Test a custom route
- # assert_recognizes {:controller => 'items', :action => 'show', :id => '1'}, 'view/item1'
+ # assert_recognizes({:controller => 'items', :action => 'show', :id => '1'}, 'view/item1')
#
# # Check a Simply RESTful generated route
# assert_recognizes list_items_url, 'items/list'
@@ -103,7 +103,7 @@ def assert_generates(expected_path, options, defaults={}, extras = {}, message=n
# assert_routing '/home', :controller => 'home', :action => 'index'
#
# # Test a route generated with a specific controller, action, and parameter (id)
- # assert_routing '/entries/show/23', :controller => 'entries', :action => 'show', id => 23
+ # assert_routing '/entries/show/23', :controller => 'entries', :action => 'show', :id => 23
#
# # Assert a basic route (controller + default action), with an error message if it fails
# assert_routing '/store', { :controller => 'store', :action => 'index' }, {}, {}, 'Route for store index not generated properly'
@@ -112,7 +112,7 @@ def assert_generates(expected_path, options, defaults={}, extras = {}, message=n
# assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"}
#
# # Tests a route with a HTTP method
- # assert_routing { :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" }
+ # assert_routing({ :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" })
def assert_routing(path, options, defaults={}, extras={}, message=nil)
assert_recognizes(options, path, extras, message)
View
3 actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -55,6 +55,9 @@ def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block)
# * Any other key creates standard HTML attributes for the tag.
#
# ==== Examples
+ # select_tag "people", options_from_collection_for_select(@people, "name", "id")
+ # # <select id="people" name="people"><option value="1">David</option></select>
+ #
# select_tag "people", "<option>David</option>"
# # => <select id="people" name="people"><option>David</option></select>
#
View
2 actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -22,7 +22,7 @@ module SanitizeHelper
#
# Custom Use (only the mentioned tags and attributes are allowed, nothing else)
#
- # <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style)
+ # <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style) %>
#
# Add table tags to the default allowed tags
#
View
6 actionpack/lib/action_view/helpers/text_helper.rb
@@ -226,8 +226,7 @@ def word_wrap(text, *args)
# Returns the text with all the Textile[http://www.textism.com/tools/textile] codes turned into HTML tags.
#
# You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
- # <i>This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
- # is available</i>.
+ # <i>This method is only available if RedCloth[http://redcloth.org/] is available</i>.
#
# ==== Examples
# textilize("*This is Textile!* Rejoice!")
@@ -263,8 +262,7 @@ def textilize(text, *options)
# but without the bounding <p> tag that RedCloth adds.
#
# You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
- # <i>This method is requires RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
- # to be available</i>.
+ # <i>This method is only available if RedCloth[http://redcloth.org/] is available</i>.
#
# ==== Examples
# textilize_without_paragraph("*This is Textile!* Rejoice!")
View
68 activemodel/README
@@ -1,21 +1,57 @@
-Active Model
-==============
+= Active Model - defined interfaces for Rails
-Totally experimental library that aims to extract common model mixins from
-ActiveRecord for use in ActiveResource (and other similar libraries).
-This is in a very rough state (no autotest or spec rake tasks set up yet),
-so please excuse the mess.
+Prior to Rails 3.0, if a plugin or gem developer wanted to be able to have
+an object interact with Action Pack helpers, it was required to either
+copy chunks of code from Rails, or monkey patch entire helpers to make them
+handle objects that did not look like Active Record. This generated code
+duplication and fragile applications that broke on upgrades.
-Here's what I plan to extract:
- * ActiveModel::Observing
- * ActiveModel::Callbacks
- * ActiveModel::Validations
+Active Model is a solution for this problem.
- # for ActiveResource params and ActiveRecord options
- * ActiveModel::Scoping
+Active Model provides a known set of interfaces that your objects can implement
+to then present a common interface to the Action Pack helpers. You can include
+functionality from the following modules:
- # to_json, to_xml, etc
- * ActiveModel::Serialization
+* Adding callbacks to your class
+
+ class MyClass
+ extend ActiveModel::Callbacks
+ define_model_callbacks :create
+
+ def create
+ _run_create_callbacks do
+ # Your create action methods here
+ end
+ end
+ end
+
+ ...gives you before_create, around_create and after_create class methods that
+ wrap your create method.
+
+ {Learn more}[link:classes/ActiveModel/CallBacks.html]
+
+* For classes that already look like an Active Record object
+
+ class MyClass
+ include ActiveModel::Conversion
+ end
+
+ ...returns the class itself when sent :to_model
+
+* Tracking changes in your object
+
+ Provides all the value tracking features implemented by ActiveRecord...
+
+ person = Person.new
+ person.name # => nil
+ person.changed? # => false
+ person.name = 'bob'
+ person.changed? # => true
+ person.changed # => ['name']
+ person.changes # => { 'name' => [nil, 'bob'] }
+ person.name = 'robert'
+ person.save
+ person.previous_changes # => {'name' => ['bob, 'robert']}
+
+ {Learn more}[link:classes/ActiveModel/Dirty.html]
-I'm trying to keep ActiveRecord compatibility where possible, but I'm
-annotating the spots where I'm diverging a bit.
View
104 activemodel/lib/active_model/callbacks.rb
@@ -1,50 +1,92 @@
require 'active_support/callbacks'
module ActiveModel
+ # == Active Model Callbacks
+ #
+ # Provides an interface for any class to have Active Record like callbacks.
+ #
+ # Like the Active Record methods, the call back chain is aborted as soon as
+ # one of the methods in the chain returns false.
+ #
+ # First, extend ActiveModel::Callbacks from the class you are creating:
+ #
+ # class MyModel
+ # extend ActiveModel::Callbacks
+ # end
+ #
+ # Then define a list of methods that you want call backs attached to:
+ #
+ # define_model_callbacks :create, :update
+ #
+ # This will provide all three standard callbacks (before, around and after) around
+ # both the :create and :update methods. To implement, you need to wrap the methods
+ # you want call backs on in a block so that the call backs get a chance to fire:
+ #
+ # def create
+ # _run_create_callbacks do
+ # # Your create action methods here
+ # end
+ # end
+ #
+ # The _run_<method_name>_callbacks methods are dynamically created when you extend
+ # the <tt>ActiveModel::Callbacks</tt> module.
+ #
+ # Then in your class, you can use the +before_create+, +after_create+ and +around_create+
+ # methods, just as you would in an Active Record module.
+ #
+ # before_create :action_before_create
+ #
+ # def action_before_create
+ # # Your code here
+ # end
+ #
+ # You can choose not to have all three callbacks by passing an hash to the
+ # define_model_callbacks method.
+ #
+ # define_model_callbacks :create, :only => :after, :before
+ #
+ # Would only create the after_create and before_create callback methods in your
+ # class.
module Callbacks
def self.extended(base)
base.class_eval do
include ActiveSupport::Callbacks
end
end
- # Define callbacks similar to ActiveRecord ones. It means:
- #
- # * The callback chain is aborted whenever the block given to
- # _run_callbacks returns false.
- #
- # * If a class is given to the fallback, it will search for
- # before_create, around_create and after_create methods.
- #
- # == Usage
- #
- # First you need to define which callbacks your model will have:
+ # define_model_callbacks accepts all options define_callbacks does, in case you
+ # want to overwrite a default. Besides that, it also accepts an :only option,
+ # where you can choose if you want all types (before, around or after) or just some.
#
+ # define_model_callbacks :initializer, :only => :after
+ #
+ # Note, the <tt>:only => <type></tt> hash will apply to all callbacks defined on
+ # that method call. To get around this you can call the define_model_callbacks
+ # method as many times as you need.
+ #
+ # define_model_callbacks :create, :only => :after
+ # define_model_callbacks :update, :only => :before
+ # define_model_callbacks :destroy, :only => :around
+ #
+ # Would create +after_create+, +before_update+ and +around_destroy+ methods only.
+ #
+ # You can pass in a class to before_<type>, after_<type> and around_<type>, in which
+ # case the call back will call that class's <action>_<type> method passing the object
+ # that the callback is being called on.
+ #
# class MyModel
+ # extend ActiveModel::Callbacks
# define_model_callbacks :create
+ #
+ # before_create AnotherClass
# end
- #
- # This will define three class methods: before_create, around_create,
- # and after_create. They accept a symbol, a string, an object or a block.
- #
- # After you create a callback, you need to tell when they are executed.
- # For example, you could do:
- #
- # def create
- # _run_create_callbacks do
- # super
+ #
+ # class AnotherClass
+ # def self.before_create( obj )
+ # # obj is the MyModel instance that the callback is being called on
# end
# end
- #
- # == Options
- #
- # define_model_callbacks accepts all options define_callbacks does, in
- # case you want to overwrite a default. Besides that, it also accepts
- # an :only option, where you can choose if you want all types (before,
- # around or after) or just some:
- #
- # define_model_callbacks :initializer, :only => :after
- #
+ #
def define_model_callbacks(*callbacks)
options = callbacks.extract_options!
options = { :terminator => "result == false", :scope => [:kind, :name] }.merge(options)
View
13 activemodel/lib/active_model/conversion.rb
@@ -1,5 +1,16 @@
module ActiveModel
- # Include ActiveModel::Conversion if your object "acts like an ActiveModel model".
+ # If your object is already designed to implement all of the Active Model featurs
+ # include this module in your Class.
+ #
+ # class MyClass
+ # include ActiveModel::Conversion
+ # end
+ #
+ # Returns self to the <tt>:to_model</tt> method.
+ #
+ # If your model does not act like an Active Model object, then you should define
+ # <tt>:to_model</tt> yourself returning a proxy object that wraps your object
+ # with Active Model compliant methods.
module Conversion
def to_model
self
View
40 activemodel/lib/active_model/dirty.rb
@@ -1,5 +1,43 @@
module ActiveModel
- # Track unsaved attribute changes.
+ # <tt>ActiveModel::Dirty</tt> provides a way to track changes in your
+ # object in the same way as ActiveRecord does.
+ #
+ # The requirements to implement ActiveModel::Dirty are:
+ #
+ # * <tt>include ActiveModel::Dirty</tt> in your object
+ # * Call <tt>define_attribute_methods</tt> passing each method you want to track
+ # * Call <tt>attr_name_will_change!</tt> before each change to the tracked attribute
+ #
+ # If you wish to also track previous changes on save or update, you need to add
+ #
+ # @previously_changed = changes
+ #
+ # inside of your save or update method.
+ #
+ # A minimal implementation could be:
+ #
+ # class Person
+ #
+ # include ActiveModel::Dirty
+ #
+ # define_attribute_methods [:name]
+ #
+ # def name
+ # @name
+ # end
+ #
+ # def name=(val)
+ # name_will_change!
+ # @name = val
+ # end
+ #
+ # def save
+ # @previously_changed = changes
+ # end
+ #
+ # end
+ #
+ # == Examples:
#
# A newly instantiated object is unchanged:
# person = Person.find_by_name('Uncle Bob')
View
8 activemodel/lib/active_model/validations/length.rb
@@ -57,13 +57,13 @@ module ClassMethods
#
# class Person < ActiveRecord::Base
# validates_length_of :first_name, :maximum=>30
- # validates_length_of :last_name, :maximum=>30, :message=>"less than {{count}} if you don't mind"
+ # validates_length_of :last_name, :maximum=>30, :message=>"less than 30 if you don't mind"
# validates_length_of :fax, :in => 7..32, :allow_nil => true
# validates_length_of :phone, :in => 7..32, :allow_blank => true
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
- # validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least {{count}} character"
- # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {{count}} characters... don't play me."
- # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {{count}} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
+ # validates_length_of :zip_code, :minimum => 5, :too_short => "please enter at least 5 characters"
+ # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with 4 characters... don't play me."
+ # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
# end
#
# Configuration options:
View
8 activerecord/lib/active_record/associations.rb
@@ -774,13 +774,12 @@ module ClassMethods
# [collection.build(attributes = {}, ...)]
# Returns one or more new objects of the collection type that have been instantiated
# with +attributes+ and linked to this object through a foreign key, but have not yet
- # been saved. <b>Note:</b> This only works if an associated object already exists, not if
- # it's +nil+!
+ # been saved.
# [collection.create(attributes = {})]
# Returns a new object of the collection type that has been instantiated
# with +attributes+, linked to this object through a foreign key, and that has already
- # been saved (if it passed the validation). <b>Note:</b> This only works if an associated
- # object already exists, not if it's +nil+!
+ # been saved (if it passed the validation). *Note*: This only works if the base model
+ # already exists in the DB, not if it is a new (unsaved) record!
#
# (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
@@ -1040,7 +1039,6 @@ def has_one(association_id, options = {})
# A Post class declares <tt>belongs_to :author</tt>, which will add:
# * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
# * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
- # * <tt>Post#author?</tt> (similar to <tt>post.author == some_author</tt>)
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
# The declaration can also include an options hash to specialize the behavior of the association.
View
4 activerecord/lib/active_record/base.rb
@@ -1724,10 +1724,10 @@ def attribute_condition(quoted_column_name, argument)
# class Article < ActiveRecord::Base
# def self.find_with_scope
# with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do
- # with_scope(:find => { :limit => 10 })
+ # with_scope(:find => { :limit => 10 }) do
# find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
# end
- # with_scope(:find => { :conditions => "author_id = 3" })
+ # with_scope(:find => { :conditions => "author_id = 3" }) do
# find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
# end
# end
View
3 activerecord/lib/active_record/fixtures.rb
@@ -335,7 +335,6 @@ class FixtureClassNotFound < StandardError #:nodoc:
# george:
# id: 1
# name: George the Monkey
-# pirate_id: 1
#
# ### in fruits.yml
#
@@ -370,8 +369,8 @@ class FixtureClassNotFound < StandardError #:nodoc:
# ### in monkeys.yml
#
# george:
+# id: 1
# name: George the Monkey
-# pirate: reginald
# fruits: apple, orange, grape
#
# ### in fruits.yml
View
3 activerecord/lib/active_record/migration.rb
@@ -1,7 +1,8 @@
require 'active_support/core_ext/object/metaclass'
module ActiveRecord
- class IrreversibleMigration < ActiveRecordError#:nodoc:
+ # Exception that can be raised to stop migrations from going backwards.
+ class IrreversibleMigration < ActiveRecordError
end
class DuplicateMigrationVersionError < ActiveRecordError#:nodoc:
View
10 activerecord/lib/active_record/nested_attributes.rb
@@ -49,14 +49,14 @@ class TooManyRecords < ActiveRecordError
# create the member and avatar in one go:
#
# params = { :member => { :name => 'Jack', :avatar_attributes => { :icon => 'smiling' } } }
- # member = Member.create(params)
+ # member = Member.create(params[:member])
# member.avatar.id # => 2
# member.avatar.icon # => 'smiling'
#
# It also allows you to update the avatar through the member:
#
- # params = { :member' => { :avatar_attributes => { :id => '2', :icon => 'sad' } } }
- # member.update_attributes params['member']
+ # params = { :member => { :avatar_attributes => { :id => '2', :icon => 'sad' } } }
+ # member.update_attributes params[:member]
# member.avatar.icon # => 'sad'
#
# By default you will only be able to set and update attributes on the
@@ -75,7 +75,7 @@ class TooManyRecords < ActiveRecordError
# member.avatar_attributes = { :id => '2', :_destroy => '1' }
# member.avatar.marked_for_destruction? # => true
# member.save
- # member.avatar #=> nil
+ # member.reload.avatar #=> nil
#
# Note that the model will _not_ be destroyed until the parent is saved.
#
@@ -179,7 +179,7 @@ class TooManyRecords < ActiveRecordError
# member.posts.detect { |p| p.id == 2 }.marked_for_destruction? # => true
# member.posts.length #=> 2
# member.save
- # member.posts.length # => 1
+ # member.reload.posts.length # => 1
#
# === Saving
#
View
7 activeresource/lib/active_resource/base.rb
@@ -42,6 +42,13 @@ module ActiveResource
# self.element_name = "person"
# end
#
+ # If your Active Resource object is required to use an HTTP proxy you can set the +proxy+ value which holds a URI.
+ #
+ # class PersonResource < ActiveResource::Base
+ # self.site = "http://api.people.com:3000/"
+ # self.proxy = "http://user:password@proxy.people.com:8080"
+ # end
+ #
#
# == Lifecycle methods
#
View
2 activesupport/lib/active_support/callbacks.rb
@@ -531,7 +531,7 @@ def reset_callbacks(symbol)
# to change this behavior.
#
# * <tt>:scope</tt> - Show which methods should be executed when a class
- # is giben as callback:
+ # is given as callback:
#
# define_callbacks :filters, :scope => [ :kind ]
#
View
2 activesupport/lib/active_support/core_ext/array/access.rb
@@ -4,7 +4,7 @@ class Array
# %w( a b c d ).from(0) # => %w( a b c d )
# %w( a b c d ).from(2) # => %w( c d )
# %w( a b c d ).from(10) # => nil
- # %w().from(0) # => nil
+ # %w().from(0) # => %w()
def from(position)
self[position..-1]
end
View
9 activesupport/lib/active_support/core_ext/array/wrap.rb
@@ -1,6 +1,15 @@
class Array
# Wraps the object in an Array unless it's an Array. Converts the
# object to an Array using #to_ary if it implements that.
+ #
+ # It differs with Array() in that it does not call +to_a+ on
+ # the argument:
+ #
+ # Array(:foo => :bar) # => [[:foo, :bar]]
+ # Array.wrap(:foo => :bar) # => [{:foo => :bar}]
+ #
+ # Array("foo\nbar") # => ["foo\n", "bar"], in Ruby 1.8
+ # Array.wrap("foo\nbar") # => ["foo\nbar"]
def self.wrap(object)
if object.nil?
[]
View
48 activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -69,6 +69,54 @@ def content_type
)
end
+ # Returns a string containing an XML representation of its receiver:
+ #
+ # {"foo" => 1, "bar" => 2}.to_xml
+ # # =>
+ # # <?xml version="1.0" encoding="UTF-8"?>
+ # # <hash>
+ # # <foo type="integer">1</foo>
+ # # <bar type="integer">2</bar>
+ # # </hash>
+ #
+ # To do so, the method loops over the pairs and builds nodes that depend on
+ # the _values_. Given a pair +key+, +value+:
+ #
+ # * If +value+ is a hash there's a recursive call with +key+ as <tt>:root</tt>.
+ #
+ # * If +value+ is an array there's a recursive call with +key+ as <tt>:root</tt>,
+ # and +key+ singularized as <tt>:children</tt>.
+ #
+ # * If +value+ is a callable object it must expect one or two arguments. Depending
+ # on the arity, the callable is invoked with the +options+ hash as first argument
+ # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. Its
+ # return value becomes a new node.
+ #
+ # * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
+ #
+ # * Otherwise, a node with +key+ as tag is created with a string representation of
+ # +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
+ # Unless the option <tt>:skip_types</tt> exists and is true, an attribute "type" is
+ # added as well according to the following mapping:
+ #
+ # XML_TYPE_NAMES = {
+ # "Symbol" => "symbol",
+ # "Fixnum" => "integer",
+ # "Bignum" => "integer",
+ # "BigDecimal" => "decimal",
+ # "Float" => "float",
+ # "TrueClass" => "boolean",
+ # "FalseClass" => "boolean",
+ # "Date" => "date",
+ # "DateTime" => "datetime",
+ # "Time" => "datetime"
+ # }
+ #
+ # By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
+ #
+ # The default XML builder is a fresh instance of <tt>Builder::XmlMarkup</tt>. You can
+ # configure your own builder with the <tt>:builder</tt> option. The method also accepts
+ # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
def to_xml(options = {})
require 'builder' unless defined?(Builder)
View
8 activesupport/lib/active_support/core_ext/hash/except.rb
@@ -3,6 +3,14 @@ class Hash
# limiting a set of parameters to everything but a few known toggles:
#
# @person.update_attributes(params[:person].except(:admin))
+ #
+ # If the receiver responds to +convert_key+, the method is called on each of the
+ # arguments. This allows +except+ to play nice with hashes with indifferent access
+ # for instance:
+ #
+ # {:a => 1}.with_indifferent_access.except(:a) # => {}
+ # {:a => 1}.with_indifferent_access.except("a") # => {}
+ #
def except(*keys)
dup.except!(*keys)
end
View
5 activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
@@ -1,6 +1,11 @@
require 'active_support/hash_with_indifferent_access'
class Hash
+
+ # Returns an +ActiveSupport::HashWithIndifferentAccess+ out of its receiver:
+ #
+ # {:a => 1}.with_indifferent_access["a"] # => 1
+ #
def with_indifferent_access
hash = ActiveSupport::HashWithIndifferentAccess.new(self)
hash.default = self.default
View
6 activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -15,15 +15,17 @@ def stringify_keys!
self
end
- # Return a new hash with all keys converted to symbols.
+ # Return a new hash with all keys converted to symbols, as long as
+ # they respond to +to_sym+.
def symbolize_keys
inject({}) do |options, (key, value)|
options[(key.to_sym rescue key) || key] = value
options
end
end
- # Destructively convert all keys to symbols.
+ # Destructively convert all keys to symbols, as long as they respond
+ # to +to_sym+.
def symbolize_keys!
self.replace(self.symbolize_keys)
end
View
16 activesupport/lib/active_support/core_ext/object/duplicable.rb
@@ -1,3 +1,19 @@
+# Most objects are cloneable, but not all. For example you can't dup +nil+:
+#
+# nil.dup # => TypeError: can't dup NilClass
+#
+# Classes may signal their instances are not duplicable removing +dup+/+clone+
+# or raising exceptions from them. So, to dup an arbitrary object you normally
+# use an optimistic approach and are ready to catch an exception, say:
+#
+# arbitrary_object.dup rescue object
+#
+# Rails dups objects in a few critical spots where they are not that arbitrary.
+# That rescue is very expensive (like 40 times slower than a predicate), and it
+# is often triggered.
+#
+# That's why we hardcode the following cases and check duplicable? instead of
+# using that rescue idiom.
class Object
# Can you safely .dup this object?
# False for nil, false, true, symbols, numbers, class and module objects; true otherwise.
View
5 activesupport/lib/active_support/core_ext/rexml.rb
@@ -2,7 +2,10 @@
# Fixes the rexml vulnerability disclosed at:
# http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/
-# This fix is identical to rexml-expansion-fix version 1.0.1
+# This fix is identical to rexml-expansion-fix version 1.0.1.
+#
+# We still need to distribute this fix because albeit the REXML
+# in recent 1.8.7s is patched, it wasn't in early patchlevels.
require 'rexml/rexml'
# Earlier versions of rexml defined REXML::Version, newer ones REXML::VERSION
View
4 activesupport/lib/active_support/core_ext/string/access.rb
@@ -7,7 +7,7 @@ class String
# Examples:
# "hello".at(0) # => "h"
# "hello".at(4) # => "o"
- # "hello".at(10) # => nil
+ # "hello".at(10) # => ERROR if < 1.9, nil in 1.9
def at(position)
mb_chars[position, 1].to_s
end
@@ -17,7 +17,7 @@ def at(position)
# Examples:
# "hello".from(0) # => "hello"
# "hello".from(2) # => "llo"
- # "hello".from(10) # => nil
+ # "hello".from(10) # => "" if < 1.9, nil in 1.9
def from(position)
mb_chars[position..-1].to_s
end
View
2 activesupport/lib/active_support/multibyte/chars.rb
@@ -385,7 +385,7 @@ def ord
# Convert characters in the string to uppercase.
#
# Example:
- # 'Laurent, òu sont les tests?'.mb_chars.upcase.to_s #=> "LAURENT, ÒU SONT LES TESTS?"
+ # 'Laurent, sont les tests ?'.mb_chars.upcase.to_s #=> "LAURENT, SONT LES TESTS ?"
def upcase
apply_mapping :uppercase_mapping
end
View
62 railties/README
@@ -1,7 +1,7 @@
== Welcome to Rails
-Rails is a web-application framework that includes everything needed to create
-database-backed web applications according to the Model-View-Control pattern.
+Rails is a web-application framework that includes everything needed to create
+database-backed web applications according to the Model-View-Control pattern.
This pattern splits the view (also called the presentation) into "dumb" templates
that are primarily responsible for inserting pre-built data in between HTML tags.
@@ -46,9 +46,9 @@ getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
More info at: http://mongrel.rubyforge.org
Other ruby web servers exist which can run your rails application, however script/server does
-not search for them or start them. These include Thin, Ebb, and Apache with mod_rails.
+not search for them or start them. These include {Thin}[http://code.macournoyer.com/thin/], {Ebb}[http://ebb.rubyforge.org/], and Apache with {mod_rails}[http://www.modrails.com/].
-For production use, often a web/proxy server such as Apache, LiteSpeed, Lighttpd or IIS is
+For production use, often a web/proxy server such as {Apache}[http://apache.org], {Nginx}[http://nginx.net/], {LiteSpeed}[http://litespeedtech.com/], {Lighttpd}[http://www.lighttpd.net/] or {IIS}[http://www.iis.net/] is
deployed as the front-end server, with the chosen ruby web server running in the back-end
and receiving the proxied requests via one of several protocols (HTTP, CGI, FCGI).
@@ -131,7 +131,7 @@ and also on programming in general.
Debugger support is available through the debugger command when you start your Mongrel or
Webrick server with --debugger. This means that you can break out of execution at any point
-in the code, investigate and change the model, AND then resume execution!
+in the code, investigate and change the model, AND then resume execution!
You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
Example:
@@ -163,13 +163,20 @@ Finally, when you're ready to resume execution, you enter "cont"
== Console
-You can interact with the domain model by starting the console through <tt>script/console</tt>.
-Here you'll have all parts of the application configured, just like it is when the
+The console is a ruby shell, which allows you to interact with your application's domain
+model. Here you'll have all parts of the application configured, just like it is when the
application is running. You can inspect domain models, change values, and save to the
database. Starting the script without arguments will launch it in the development environment.
-Passing an argument will specify a different environment, like <tt>script/console production</tt>.
-To reload your controllers and models after launching the console run <tt>reload!</tt>
+To start the console, just run <tt>script/console</tt> from the application directory.
+
+Options:
+
+* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications made to the database.
+* Passing an environment name as an argument will load the corresponding environment.
+ Example: <tt>script/console production</tt>.
+
+More information about irb can be found at link:http://www.rubycentral.com/pickaxe/irb.html
== dbconsole
@@ -181,6 +188,43 @@ Currently works for mysql, postgresql and sqlite.
== Description of Contents
+The default directory structure of a generated Ruby on Rails applicartion:
+
+ |-- app
+ | |-- controllers
+ | |-- helpers
+ | |-- models
+ | `-- views
+ | `-- layouts
+ |-- config
+ | |-- environments
+ | |-- initializers
+ | `-- locales
+ |-- db
+ |-- doc
+ |-- lib
+ | `-- tasks
+ |-- log
+ |-- public
+ | |-- images
+ | |-- javascripts
+ | `-- stylesheets
+ |-- script
+ | `-- performance
+ |-- test
+ | |-- fixtures
+ | |-- functional
+ | |-- integration
+ | |-- performance
+ | `-- unit
+ |-- tmp
+ | |-- cache
+ | |-- pids
+ | |-- sessions
+ | `-- sockets
+ `-- vendor
+ `-- plugins
+
app
Holds all the code that's specific to this particular application.
View
15 railties/guides/rails_guides.rb
@@ -1,5 +1,8 @@
pwd = File.dirname(__FILE__)
-$: << pwd
+$:.unshift pwd
+
+# Loading Action Pack requires rack and erubis.
+require 'rubygems'
begin
as_lib = File.join(pwd, "../../activesupport/lib")
@@ -11,15 +14,13 @@
require "action_controller"
require "action_view"
rescue LoadError
- require 'rubygems'
gem "actionpack", '>= 2.3'
require "action_controller"
require "action_view"
end
begin
- require 'rubygems'
gem 'RedCloth', '>= 4.1.1'
rescue Gem::LoadError
$stderr.puts %(Generating Guides requires RedCloth 4.1.1+)
@@ -29,11 +30,11 @@
require 'redcloth'
module RailsGuides
- autoload :Generator, "rails_guides/generator"
- autoload :Indexer, "rails_guides/indexer"
- autoload :Helpers, "rails_guides/helpers"
+ autoload :Generator, "rails_guides/generator"
+ autoload :Indexer, "rails_guides/indexer"
+ autoload :Helpers, "rails_guides/helpers"
autoload :TextileExtensions, "rails_guides/textile_extensions"
- autoload :Levenshtein, "rails_guides/levenshtein"
+ autoload :Levenshtein, "rails_guides/levenshtein"
end
RedCloth.send(:include, RailsGuides::TextileExtensions)
View
14 railties/guides/rails_guides/generator.rb
@@ -1,5 +1,11 @@
require 'set'
+class String
+ def html_safe!
+ self
+ end unless "post 9415935902f120a9bac0bfce7129725a0db38ed3".respond_to?(:html_safe!)
+end
+
module RailsGuides
class Generator
attr_reader :output, :view_path, :view, :guides_dir
@@ -18,7 +24,7 @@ def initialize(output = nil)
end
def generate
- guides = Dir.entries(view_path).find_all {|g| g =~ /textile$/ }
+ guides = Dir.entries(view_path).find_all {|g| g =~ /\.textile(?:\.erb)?$/ }
if ENV["ONLY"]
only = ENV["ONLY"].split(",").map{|x| x.strip }.map {|o| "#{o}.textile" }
@@ -36,7 +42,7 @@ def generate
end
def generate_guide(guide)
- guide =~ /(.*?)(\.erb)?\.textile/
+ guide =~ /(.*?)\.textile(?:\.erb)?$/
name = $1
puts "Generating #{name}"
@@ -46,7 +52,7 @@ def generate_guide(guide)
@view = ActionView::Base.new(view_path)
@view.extend(Helpers)
- if guide =~ /\.erb\.textile/
+ if guide =~ /\.textile\.erb$/
# Generate the erb pages with textile formatting - e.g. index/authors
result = view.render(:layout => 'layout', :file => guide)
f.write textile(result)
@@ -55,7 +61,7 @@ def generate_guide(guide)
body = set_header_section(body, @view)
body = set_index(body, @view)
- result = view.render(:layout => 'layout', :text => textile(body))
+ result = view.render(:layout => 'layout', :text => textile(body).html_safe!)
f.write result
warn_about_broken_links(result) if ENV.key?("WARN_BROKEN_LINKS")
end
View
18 railties/guides/source/2_2_release_notes.textile
@@ -18,7 +18,7 @@ Rails 2.2 supplies an easy system for internationalization (or i18n, for those o
* More information :
** "Official Rails i18 website":http://rails-i18n.org
** "Finally. Ruby on Rails gets internationalized":http://www.artweb-design.de/2008/7/18/finally-ruby-on-rails-gets-internationalized
-** "Localizing Rails : Demo application":http://i18n-demo.phusion.nl
+** "Localizing Rails : Demo application":http://github.com/clemens/i18n_demo_app
h4. Compatibility with Ruby 1.9 and JRuby
@@ -28,20 +28,20 @@ h3. Documentation
The internal documentation of Rails, in the form of code comments, has been improved in numerous places. In addition, the "Ruby on Rails Guides":http://guides.rubyonrails.org/ project is the definitive source for information on major Rails components. In its first official release, the Guides page includes:
-* "Getting Started with Rails":http://guides.rubyonrails.org/getting_started_with_rails.html
+* "Getting Started with Rails":http://guides.rubyonrails.org/getting_started.html
* "Rails Database Migrations":http://guides.rubyonrails.org/migrations.html
* "Active Record Associations":http://guides.rubyonrails.org/association_basics.html
-* "Active Record Finders":http://guides.rubyonrails.org/finders.html
+* "Active Record Query Interface":http://guides.rubyonrails.org/active_record_querying.html
* "Layouts and Rendering in Rails":http://guides.rubyonrails.org/layouts_and_rendering.html
* "Action View Form Helpers":http://guides.rubyonrails.org/form_helpers.html
-* "Rails Routing from the Outside In":http://guides.rubyonrails.org/routing_outside_in.html
-* "Basics of Action Controller":http://guides.rubyonrails.org/actioncontroller_basics.html
+* "Rails Routing from the Outside In":http://guides.rubyonrails.org/routing.html
+* "Action Controller Overview":http://guides.rubyonrails.org/action_controller_overview.html
* "Rails Caching":http://guides.rubyonrails.org/caching_with_rails.html
-* "Testing Rails Applications":http://guides.rubyonrails.org/testing_rails_applications.html
+* "A Guide to Testing Rails Applications":http://guides.rubyonrails.org/testing.html
* "Securing Rails Applications":http://guides.rubyonrails.org/security.html
* "Debugging Rails Applications":http://guides.rubyonrails.org/debugging_rails_applications.html
-* "Benchmarking and Profiling Rails Applications":http://guides.rubyonrails.org/benchmarking_and_profiling.html
-* "The Basics of Creating Rails Plugins":http://guides.rubyonrails.org/creating_plugins.html
+* "Performance Testing Rails Applications":http://guides.rubyonrails.org/performance_testing.html
+* "The Basics of Creating Rails Plugins":http://guides.rubyonrails.org/plugins.html
All told, the Guides provide tens of thousands of words of guidance for beginning and intermediate Rails developers.
@@ -229,7 +229,7 @@ This will enable recognition of (among others) these routes:
* Lead Contributor: "S. Brent Faulkner":http://www.unwwwired.net/
* More information:
-** "Rails Routing from the Outside In":http://guides.rails.info/routing/routing_outside_in.html#_nested_resources
+** "Rails Routing from the Outside In":http://guides.rubyonrails.org/routing.html#_nested_resources
** "What's New in Edge Rails: Shallow Routes":http://ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-shallow-routes
h4. Method Arrays for Member or Collection Routes
View
6 railties/guides/source/2_3_release_notes.textile
@@ -81,7 +81,7 @@ accepts_nested_attributes_for :author,
:reject_if => proc { |attributes| attributes['name'].blank? }
</ruby>
-* Lead Contributor: "Eloy Duran":http://www.superalloy.nl/blog/
+* Lead Contributor: "Eloy Duran":http://superalloy.nl/
* More Information: "Nested Model Forms":http://weblog.rubyonrails.org/2009/1/26/nested-model-forms
h4. Nested Transactions
@@ -365,10 +365,10 @@ You can write this view in Rails 2.3:
<% end %>
</erb>
-* Lead Contributor: "Eloy Duran":http://www.superalloy.nl/blog/
+* Lead Contributor: "Eloy Duran":http://superalloy.nl/
* More Information:
** "Nested Model Forms":http://weblog.rubyonrails.org/2009/1/26/nested-model-forms
-** "complex-form-examples":http://github.com/alloy/complex-form-examples/tree/nested_attributes
+** "complex-form-examples":http://github.com/alloy/complex-form-examples
** "What's New in Edge Rails: Nested Object Forms":http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes
h4. Smart Rendering of Partials
View
4 railties/guides/source/action_mailer_basics.textile
@@ -402,8 +402,6 @@ Testing mailers normally involves two things: One is that the mail was queued, a
<ruby>
class UserMailerTest < ActionMailer::TestCase
- tests UserMailer
-
def test_welcome_email
user = users(:some_user_in_your_fixtures)
@@ -412,7 +410,7 @@ class UserMailerTest < ActionMailer::TestCase
assert !ActionMailer::Base.deliveries.empty?
# Test the body of the sent email contains what we expect it to
- assert_equal [@user.email], email.to
+ assert_equal [user.email], email.to
assert_equal "Welcome to My Awesome Site", email.subject
assert_match /Welcome to example.com, #{user.first_name}/, email.body
end
View
1,434 railties/guides/source/action_view_overview.textile
@@ -2,49 +2,1460 @@ h2. Action View Overview
In this guide you will learn:
-* What Action View is, and how to use it
+* What Action View is, and how to use it with Rails
+* How to use Action View outside of Rails
+* How best to use templates, partials, and layouts
+* What helpers are provided by Action View, and how to make your own
+* How to use localized views
endprologue.
h3. What is Action View?
-TODO...
+Action View and Action Controller are the two major components of Action Pack. In Rails, web requests are handled by Action Pack, which splits the work into a controller part (performing the logic) and a view part (rendering a template). Typically, Action Controller will be concerned with communicating with the database and performing CRUD actions where necessary. Action View is then responsible for compiling the response.
+
+Action View templates are written using embedded Ruby in tags mingled with HTML. To avoid cluttering the templates with boilerplate code, a number of helper classes provide common behavior for forms, dates, and strings. It's also easy to add new helpers to your application as it evolves.
+
+Note: Some features of Action View are tied to Active Record, but that doesn't mean that Action View depends on Active Record. Action View is an independent package that can be used with any sort of backend.
h3. Using Action View with Rails
TODO...
h3. Using Action View outside of Rails
-TODO...
+Action View works well with Action Record, but it can also be used with other Ruby tools. We can demonstrate this by creating a small "Rack":http://rack.rubyforge.org/ application that includes Action View functionality. This may be useful, for example, if you'd like access to Action View's helpers in a Rack application.
+
+Let's start by ensuring that you have the Action Pack and Rack gems installed:
+
+<shell>
+gem install actionpack
+gem install rack
+</shell>
+
+Now we'll create a simple "Hello World" application that uses the +titleize+ method provided by Action View.
+
+*hello_world.rb:*
+
+<ruby>
+require 'rubygems'
+require 'action_view'
+require 'rack'
+
+def hello_world(env)
+ [200, {"Content-Type" => "text/html"}, "hello world".titleize]
+end
+
+Rack::Handler::Mongrel.run method(:hello_world), :Port => 4567
+</ruby>
+
+We can see this all come together by starting up the application and then visiting +http://localhost:4567/+
+
+<shell>
+ruby hello_world.rb
+</shell>
+
+TODO needs a screenshot? I have one - not sure where to put it.
+
+Notice how 'hello world' has been converted into 'Hello World' by the +titleize+ helper method.
+
+Action View can also be used with "Sinatra":http://www.sinatrarb.com/ in the same way.
+
+Let's start by ensuring that you have the Action Pack and Sinatra gems installed:
+
+<shell>
+gem install actionpack
+gem install sinatra
+</shell>
+
+Now we'll create the same "Hello World" application in Sinatra.
+
+*hello_world.rb:*
+
+<ruby>
+require 'rubygems'
+require 'action_view'
+require 'sinatra'
+
+get '/' do
+ erb 'hello world'.titleize
+end
+</ruby>
+
+Then, we can run the application:
+
+<shell>
+ruby hello_world.rb
+</shell>
+
+Once the application is running, you can see Sinatra and Action View working together by visiting +http://localhost:4567/+
+
+TODO needs a screenshot? I have one - not sure where to put it.
h3. Templates, Partials and Layouts
TODO...
+TODO see http://guides.rubyonrails.org/layouts_and_rendering.html
+
h3. Using Templates, Partials and Layouts in "The Rails Way"
TODO...
h3. Partial Layouts
-TODO...
+Partials can have their own layouts applied to them. These layouts are different than the ones that are specified globally for the entire action, but they work in a similar fashion.
+
+Let's say we're displaying a post on a page where it should be wrapped in a +div+ for display purposes. First, we'll create a new +Post+:
+
+<ruby>
+Post.create(:body => 'Partial Layouts are cool!')
+</ruby>
+
+In the +show+ template, we'll render the +post+ partial wrapped in the +box+ layout:
+
+*posts/show.html.erb*
+
+<ruby>
+<%= render :partial => 'post', :layout => 'box', :locals => {:post => @post} %>
+</ruby>
+
+The +box+ layout simply wraps the +post+ partial in a +div+:
+
+*posts/_box.html.erb*
+
+<ruby>
+<div class='box'>
+ <%= yield %>
+</div>
+</ruby>
+
+The +post+ partial wraps the post's +body+ in a +div+ with the +id+ of the post using the +div_for+ helper:
+
+*posts/_post.html.erb*
+
+<ruby>
+<% div_for(post) do %>
+ <p><%= post.body %></p>
+<% end %>
+</ruby>
+
+This example would output the following:
+
+<html>
+<div class='box'>
+ <div id='post_1'>
+ <p>Partial Layouts are cool!</p>
+ </div>
+</div>
+</html>
+
+Note that the partial layout has access to the local +post+ variable that was passed into the +render+ call. However, unlike application-wide layouts, partial layouts still have the underscore prefix.
+
+You can also render a block of code within a partial layout instead of calling +yield+. For example, if we didn't have the +post+ partial, we could do this instead:
+
+*posts/show.html.erb*
+
+<ruby>
+<% render(:layout => 'box', :locals => {:post => @post}) do %>
+ <% div_for(post) do %>
+ <p><%= post.body %></p>
+ <% end %>
+<% end %>
+</ruby>
+
+If we're using the same +box+ partial from above, his would produce the same output as the previous example.
h3. View Paths
TODO...
-h3. Overview of all the helpers provided by AV
+h3. Overview of all the helpers provided by Action View
-TODO...
+The following is only a brief overview summary of the helpers available in Action View. It's recommended that you review the API Documentation, which covers all of the helpers in more detail, but this should serve as a good starting point.
-h3. Localized Views
+h4. ActiveRecordHelper
-Action View has the ability render different templates depending on the current locale.
+The Active Record Helper makes it easier to create forms for records kept in instance variables. You may also want to review the "Rails Form helpers guide":form_helpers.html.
-For example, suppose you have a Posts controller with a show action. By default, calling this action will render +app/views/posts/show.html.erb+. But if you set +I18n.locale = :de+, then +app/views/posts/show.de.html.erb+ will be rendered instead. If the localized template isn't present, the undecorated version will be used. This means you're not required to provide localized views for all cases, but they will be preferred and used if available.
+h5. error_message_on
+
+Returns a string containing the error message attached to the method on the object if one exists.
+
+<ruby>
+error_message_on "post", "title"
+</ruby>
+
+h5. error_messages_for
+
+Returns a string with a DIV containing all of the error messages for the objects located as instance variables by the names given.
+
+<ruby>
+error_messages_for "post"
+</ruby>
+
+h5. form
+
+Returns a form with inputs for all attributes of the specified Active Record object. For example, let's say we have a +@post+ with attributes named +title+ of type +String+ and +body+ of type +Text+. Calling +form+ would produce a form to creating a new post with inputs for those attributes.
+
+<ruby>
+form("post")
+</ruby>
+
+<html>
+<form action='/posts/create' method='post'>
+ <p>
+ <label for="post_title">Title</label><br />
+ <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
+ </p>
+ <p>
+ <label for="post_body">Body</label><br />
+ <textarea cols="40" id="post_body" name="post[body]" rows="20"></textarea>
+ </p>
+ <input name="commit" type="submit" value="Create" />
+</form>
+</html>
+
+Typically, +form_for+ is used instead of +form+ because it doesn't automatically include all of the model's attributes.
+
+h5. input
+
+Returns a default input tag for the type of object returned by the method.
+
+For example, if +@post+ has an attribute +title+ mapped to a +String+ column that holds "Hello World":
+
+<ruby>
+input("post", "title") # =>
+ <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
+</ruby>
+
+h4. AssetTagHelper
+
+This module provides methods for generating HTML that links views to assets such as images, javascripts, stylesheets, and feeds.
+
+By default, Rails links to these assets on the current host in the public folder, but you can direct Rails to link to assets from a dedicated assets server by setting +ActionController::Base.asset_host+ in your +config/environment.rb+. For example, let's say your asset host is +assets.example.com+:
+
+<ruby>
+ActionController::Base.asset_host = "assets.example.com"
+image_tag("rails.png") # => <img src="http://assets.example.com/images/rails.png" alt="Rails" />
+</ruby>
+
+h5. register_javascript_expansion
+
+Register one or more javascript files to be included when symbol is passed to javascript_include_tag. This method is typically intended to be called from plugin initialization to register javascript files that the plugin installed in public/javascripts.
+
+<ruby>
+ActionView::Helpers::AssetTagHelper.register_javascript_expansion :monkey => ["head", "body", "tail"]
+
+javascript_include_tag :monkey # =>
+ <script type="text/javascript" src="/javascripts/head.js"></script>
+ <script type="text/javascript" src="/javascripts/body.js"></script>
+ <script type="text/javascript" src="/javascripts/tail.js"></script>
+</ruby>
+
+h5. register_javascript_include_default
+
+Register one or more additional JavaScript files to be included when +javascript_include_tag :defaults+ is called. This method is typically intended to be called from plugin initialization to register additional +.js+ files that the plugin installed in +public/javascripts+.
+
+h5. register_stylesheet_expansion
+
+Register one or more stylesheet files to be included when symbol is passed to +stylesheet_link_tag+. This method is typically intended to be called from plugin initialization to register stylesheet files that the plugin installed in +public/stylesheets+.
+
+<ruby>
+ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"]
+
+stylesheet_link_tag :monkey # =>
+ <link href="/stylesheets/head.css" media="screen" rel="stylesheet" type="text/css" />
+ <link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" />
+ <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" />
+</ruby>
+
+h5. auto_discovery_link_tag
+
+Returns a link tag that browsers and news readers can use to auto-detect an RSS or ATOM feed.
+
+<ruby>
+auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {:title => "RSS Feed"}) # =>
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="http://www.example.com/feed" />
+</ruby>
+
+h5. image_path
+
+Computes the path to an image asset in the public images directory. Full paths from the document root will be passed through. Used internally by +image_tag+ to build the image path.
+
+<ruby>
+image_path("edit.png") # => /images/edit.png
+</ruby>
+
+h5. image_tag
+
+Returns an html image tag for the source. The source can be a full path or a file that exists in your public images directory.
+
+<ruby>
+image_tag("icon.png") # => <img src="/images/icon.png" alt="Icon" />
+</ruby>
+
+h5. javascript_include_tag
+
+Returns an html script tag for each of the sources provided. You can pass in the filename (+.js+ extension is optional) of javascript files that exist in your +public/javascripts+ directory for inclusion into the current page or you can pass the full path relative to your document root.
+
+<ruby>
+javascript_include_tag "common" # =>
+ <script type="text/javascript" src="/javascripts/common.js"></script>
+</ruby>
+
+To include the Prototype and Scriptaculous javascript libraries in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +public/javascripts+ directory, it will be included as well.
+
+<ruby>
+javascript_include_tag :defaults
+</ruby>
+
+You can also include all javascripts in the javascripts directory using +:all+ as the source.
+
+<ruby>
+javascript_include_tag :all
+</ruby>
+
+You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be compressed by gzip (leading to faster transfers). Caching will only happen if +ActionController::Base.perform_caching+ is set to true (which is the case by default for the Rails production environment, but not for the development environment).
+
+<ruby>
+javascript_include_tag :all, :cache => true # =>
+ <script type="text/javascript" src="/javascripts/all.js"></script>
+</ruby>
+
+h5. javascript_path
+
+Computes the path to a javascript asset in the +public/javascripts+ directory. If the source filename has no extension, +.js+ will be appended. Full paths from the document root will be passed through. Used internally by +javascript_include_tag+ to build the script path.
+
+<ruby>
+javascript_path "common" # => /javascripts/common.js
+</ruby>
+
+h5. stylesheet_link_tag
+
+Returns a stylesheet link tag for the sources specified as arguments. If you don't specify an extension, +.css+ will be appended automatically.
+
+<ruby>
+stylesheet_link_tag "application" # =>
+ <link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
+</ruby>
+
+You can also include all styles in the stylesheet directory using :all as the source:
+
+<ruby>
+stylesheet_link_tag :all
+</ruby>
+
+You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching is set to true (which is the case by default for the Rails production environment, but not for the development environment).
+
+<ruby>
+stylesheet_link_tag :all, :cache => true
+ <link href="/stylesheets/all.css" media="screen" rel="stylesheet" type="text/css" />
+</ruby>
+
+h5. stylesheet_path
+
+Computes the path to a stylesheet asset in the public stylesheets directory. If the source filename has no extension, .css will be appended. Full paths from the document root will be passed through. Used internally by stylesheet_link_tag to build the stylesheet path.
+
+<ruby>
+stylesheet_path "application" # => /stylesheets/application.css
+</ruby>
+
+h4. AtomFeedHelper
+
+h5. atom_feed
+
+This helper makes building an ATOM feed easy. Here's a full usage example:
+
+*config/routes.rb*
+
+<ruby>
+map.resources :posts
+</ruby>
+
+*app/controllers/posts_controller.rb*
+
+<ruby>
+def index
+ @posts = Post.find(:all)
+
+ respond_to do |format|
+ format.html
+ format.atom
+ end
+end
+</ruby>
+
+*app/views/posts/index.atom.builder*
+
+<ruby>
+atom_feed do |feed|
+ feed.title("Posts Index")
+ feed.updated((@posts.first.created_at))
+
+ for post in @posts
+ feed.entry(post) do |entry|
+ entry.title(post.title)
+ entry.content(post.body, :type => 'html')
+
+ entry.author do |author|
+ author.name(post.author_name)
+ end
+ end
+ end
+end
+</ruby>
+
+h4. BenchmarkHelper
+
+h5. benchmark
+
+Allows you to measure the execution time of a block in a template and records the result to the log. Wrap this block around expensive operations or possible bottlenecks to get a time reading for the operation.
+
+<ruby>
+<% benchmark "Process data files" do %>
+ <%= expensive_files_operation %>
+<% end %>
+</ruby>
+
+This would add something like "Process data files (0.34523)" to the log, which you can then use to compare timings when optimizing your code.
+
+h4. CacheHelper
+
+h5. cache
+
+A method for caching fragments of a view rather than an entire action or page. This technique is useful caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See +ActionController::Caching::Fragments+ for more information.
+
+<ruby>
+<% cache do %>
+ <%= render :partial => "shared/footer" %>
+<% end %>
+</ruby>
+
+h4. CaptureHelper
+
+h5. capture
+
+The +capture+ method allows you to extract part of a template into a variable. You can then use this variable anywhere in your templates or layout.
+
+<ruby>
+<% @greeting = capture do %>
+ <p>Welcome! The date and time is <%= Time.now %></p>
+<% end %>
+<ruby>
+
+The captured variable can then be used anywhere else.
+
+<ruby>
+<html>
+ <head>
+ <title>Welcome!</title>
+ </head>
+ <body>
+ <%= @greeting %>
+ </body>
+</html>
+</ruby>
+
+h5. content_for
+
+Calling +content_for+ stores a block of markup in an identifier for later use. You can make subsequent calls to the stored content in other templates or the layout by passing the identifier as an argument to +yield+.
+
+For example, let's say we have a standard application layout, but also a special page that requires certain Javascript that the rest of the site doesn't need. We can use +content_for+ to include this Javascript on our special page without fattening up the rest of the site.
+
+*app/views/layouts/application.html.erb*
+
+<ruby>
+<html>
+ <head>
+ <title>Welcome!</title>
+ <%= yield :special_script %>
+ </head>
+ <body>
+ <p>Welcome! The date and time is <%= Time.now %></p>
+ </body>
+</html>
+</ruby>
+
+*app/views/posts/special.html.erb*
+
+<ruby>
+<p>This is a special page.</p>
+
+<% content_for :special_script do %>
+ <script type="text/javascript">alert('Hello!')</script>
+<% end %>
+</ruby>
+
+h4. DateHelper
+
+h5. date_select
+
+Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute.
+
+<ruby>
+date_select("post", "published_on")
+</ruby>
+
+h5. datetime_select
+
+Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based attribute.
+
+<ruby>
+datetime_select("post", "published_on")
+</ruby>
+
+h5. distance_of_time_in_words
+
+Reports the approximate distance in time between two Time or Date objects or integers as seconds. Set +include_seconds+ to true if you want more detailed approximations.
+
+<ruby>
+distance_of_time_in_words(Time.now, Time.now + 15.seconds) # => less than a minute
+distance_of_time_in_words(Time.now, Time.now + 15.seconds, true) # => less than 20 seconds
+</ruby>
+
+h5. select_date
+
+Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+ provided.
+
+<ruby>
+# Generates a date select that defaults to the date provided (six days after today)
+select_date(Time.today + 6.days)
+
+# Generates a date select that defaults to today (no specified date)
+select_date()
+</ruby>
+
+h5. select_datetime
+
+Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+ provided.
+
+<ruby>
+# Generates a datetime select that defaults to the datetime provided (four days after today)
+select_datetime(Time.now + 4.days)
+
+# Generates a datetime select that defaults to today (no specified datetime)
+select_datetime()
+</ruby>
+
+h5. select_day
+
+Returns a select tag with options for each of the days 1 through 31 with the current day selected.
+
+<ruby>
+# Generates a select field for days that defaults to the day for the date provided
+select_day(Time.today + 2.days)
+
+# Generates a select field for days that defaults to the number given
+select_day(5)
+</ruby>
+
+h5. select_hour
+
+Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
+
+<ruby>
+# Generates a select field for minutes that defaults to the minutes for the time provided
+select_minute(Time.now + 6.hours)
+</ruby>
-TODO add full code example...
+h5. select_minute
+
+Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
+
+<ruby>
+# Generates a select field for minutes that defaults to the minutes for the time provided.
+select_minute(Time.now + 6.hours)
+</ruby>
+
+h5. select_month
+
+Returns a select tag with options for each of the months January through December with the current month selected.
+
+<ruby>
+# Generates a select field for months that defaults to the current month
+select_month(Date.today)
+</ruby>
+
+h5. select_second
+
+Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
+
+<ruby>
+# Generates a select field for seconds that defaults to the seconds for the time provided
+select_second(Time.now + 16.minutes)
+</ruby>
+
+h5. select_time
+
+Returns a set of html select-tags (one for hour and minute).
+
+<ruby>
+# Generates a time select that defaults to the time provided
+select_time(Time.now)
+</ruby>
+
+h5. select_year
+
+Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius can be changed using the +:start_year+ and +:end_year+ keys in the +options+.
+
+<ruby>
+# Generates a select field for five years on either side of +Date.today+ that defaults to the current year
+select_year(Date.today)
+
+# Generates a select field from 1900 to 2009 that defaults to the current year
+select_year(Date.today, :start_year => 1900, :end_year => 2009)
+</ruby>
+
+h5. time_ago_in_words
+
+Like +distance_of_time_in_words+, but where +to_time+ is fixed to +Time.now+.
+
+<ruby>
+time_ago_in_words(3.minutes.from_now) # => 3 minutes
+</ruby>
+
+h5. time_select
+
+Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified time-based attribute. The selects are prepared for multi-parameter assignment to an Active Record object.
+
+<ruby>
+# Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted attribute
+time_select("order", "submitted")
+</ruby>
+
+h4. DebugHelper
+
+Returns a +pre+ tag that has object dumped by YAML. This creates a very readable way to inspect an object.
+
+<ruby>
+my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]}
+debug(my_hash)
+</ruby>
+
+<html>
+<pre class='debug_dump'>---
+first: 1
+second: two
+third:
+- 1
+- 2
+- 3
+</pre>
+</html>
+
+h4. FormHelper
+
+Form helpers are designed to make working with models much easier compared to using just standard HTML elements by providing a set of methods for creating forms based on your models. This helper generates the HTML for forms, providing a method for each sort of input (e.g., text, password, select, and so on). When the form is submitted (i.e., when the user hits the submit button or form.submit is called via JavaScript), the form inputs will be bundled into the params object and passed back to the controller.
+
+There are two types of form helpers: those that specifically work with model attributes and those that don't. This helper deals with those that work with model attributes; to see an example of form helpers that don‘t work with model attributes, check the ActionView::Helpers::FormTagHelper documentation.
+
+The core method of this helper, form_for, gives you the ability to create a form for a model instance; for example, let's say that you have a model Person and want to create a new instance of it:
+
+<ruby>
+# Note: a @person variable will have been created in the controller (e.g. @person = Person.new)
+<% form_for :person, @person, :url => { :action => "create" } do |f| %>
+ <%= f.text_field :first_name %>
+ <%= f.text_field :last_name %>
+ <%= submit_tag 'Create' %>
+<% end %>
+</ruby>
+
+The HTML generated for this would be:
+
+<html>
+<form action="/persons/create" method="post">
+ <input id="person_first_name" name="person[first_name]" size="30" type="text" />
+ <input id="person_last_name" name="person[last_name]" size="30" type="text" />
+ <input name="commit" type="submit" value="Create" />
+</form>
+</html>
+
+The params object created when this form is submitted would look like:
+
+<ruby>
+{"action"=>"create", "controller"=>"persons", "person"=>{"first_name"=>"William", "last_name"=>"Smith"}}
+</ruby>
+
+The params hash has a nested person value, which can therefore be accessed with params[:person] in the controller.
+
+h5. check_box
+
+Returns a checkbox tag tailored for accessing a specified attribute.
+
+<ruby>
+# Let's say that @post.validated? is 1:
+check_box("post", "validated")
+# => <input type="checkbox" id="post_validated" name="post[validated]" value="1" />
+# <input name="post[validated]" type="hidden" value="0" />
+</ruby>
+
+h5. fields_for
+
+Creates a scope around a specific model object like form_for, but doesn‘t create the form tags themselves. This makes fields_for suitable for specifying additional model objects in the same form:
+
+<ruby>
+<% form_for @person, :url => { :action => "update" } do |person_form| %>
+ First name: <%= person_form.text_field :first_name %>
+ Last name : <%= person_form.text_field :last_name %>
+
+ <% fields_for @person.permission do |permission_fields| %>
+ Admin? : <%= permission_fields.check_box :admin %>
+ <% end %>
+<% end %>
+</ruby>
+
+h5. file_field
+
+Returns an file upload input tag tailored for accessing a specified attribute.
+
+<ruby>
+file_field(:user, :avatar)
+# => <input type="file" id="user_avatar" name="user[avatar]" />
+</ruby>
+
+h5. form_for
+
+Creates a form and a scope around a specific model object that is used as a base for questioning about values for the fields.
+
+<ruby>
+<% form_for @post do |f| %>
+ <%= f.label :title, 'Title' %>:
+ <%= f.text_field :title %><br />
+ <%= f.label :body, 'Body' %>:
+ <%= f.text_area :body %><br />
+<% end %>
+</ruby>
+
+h5. hidden_field
+
+Returns a hidden input tag tailored for accessing a specified attribute.
+
+<ruby>
+hidden_field(:user, :token)
+# => <input type="hidden" id="user_token" name="user[token]" value="#{@user.token}" />
+</ruby>
+
+h5. label
+
+Returns a label tag tailored for labelling an input field for a specified attribute.
+
+<ruby>
+label(:post, :title)
+# => <label for="post_title">Title</label>
+</ruby>
+
+h5. password_field
+
+Returns an input tag of the "password" type tailored for accessing a specified attribute.
+
+<ruby>
+password_field(:login, :pass)
+# => <input type="text" id="login_pass" name="login[pass]" value="#{@login.pass}" />
+</ruby>
+
+h5. radio_button
+
+Returns a radio button tag for accessing a specified attribute.
+
+<ruby>
+# Let's say that @post.category returns "rails":
+radio_button("post", "category", "rails")
+radio_button("post", "category", "java")
+# => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" />
+# <input type="radio" id="post_category_java" name="post[category]" value="java" />
+</ruby>
+
+h5. text_area
+
+Returns a textarea opening and closing tag set tailored for accessing a specified attribute.
+
+<ruby>
+text_area(:comment, :text, :size => "20x30")
+# => <textarea cols="20" rows="30" id="comment_text" name="comment[text]">
+# #{@comment.text}
+# </textarea>
+</ruby>
+
+h5. text_field
+
+Returns an input tag of the "text" type tailored for accessing a specified attribute.
+
+<ruby>
+text_field(:post, :title)
+# => <input type="text" id="post_title" name="post[title]" value="#{@post.title}" />
+</ruby>
+
+h4. FormOptionsHelper
+
+Provides a number of methods for turning different kinds of containers into a set of option tags.
+
+h5. collection_select
+
+Returns +select+ and +option+ tags for the collection of existing return values of +method+ for +object+'s class.
+
+Example object structure for use with this method:
+
+<ruby>
+class Post < ActiveRecord::Base
+ belongs_to :author
+end
+
+class Author < ActiveRecord::Base
+ has_many :posts
+ def name_with_initial
+ "#{first_name.first}. #{last_name}"
+ end
+end
+</ruby>
+
+Sample usage (selecting the associated Author for an instance of Post, +@post+):
+
+<ruby>
+collection_select(:post, :author_id, Author.find(:all), :id, :name_with_initial, {:prompt => true})
+</ruby>
+
+If @post.author_id is already 1, this would return:
+
+<html>
+<select name="post[author_id]">
+ <option value="">Please select</option>
+ <option value="1" selected="selected">D. Heinemeier Hansson</option>
+ <option value="2">D. Thomas</option>
+ <option value="3">M. Clark</option>
+</select>
+</html>
+
+h5. country_options_for_select
+
+Returns a string of option tags for pretty much any country in the world.
+
+h5. country_select
+
+Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags.
+
+h5. option_groups_from_collection_for_select
+
+Returns a string of +option+ tags, like +options_from_collection_for_select+, but groups them by +optgroup+ tags based on the object relationships of the arguments.
+
+Example object structure for use with this method:
+
+<ruby>
+class Continent < ActiveRecord::Base
+ has_many :countries
+ # attribs: id, name
+end
+
+class Country < ActiveRecord::Base
+ belongs_to :continent
+ # attribs: id, name, continent_id
+end
+</ruby>
+
+Sample usage:
+
+<ruby>
+option_groups_from_collection_for_select(@continents, :countries, :name, :id, :name, 3)
+</ruby>
+
+TODO check above textile output looks right
+
+Possible output:
+
+<html>
+<optgroup label="Africa">
+ <option value="1">Egypt</option>
+ <option value="4">Rwanda</option>
+ ...
+</optgroup>
+<optgroup label="Asia">
+ <option value="3" selected="selected">China</option>
+ <option value="12">India</option>
+ <option value="5">Japan</option>
+ ...
+</optgroup>
+</html>
+
+Note: Only the +optgroup+ and +option+ tags are returned, so you still have to wrap the output in an appropriate +select+ tag.
+
+h5. options_for_select
+
+Accepts a container (hash, array, enumerable, your type) and returns a string of option tags.
+
+<ruby>
+options_for_select([ "VISA", "MasterCard" ])
+# => <option>VISA</option> <option>MasterCard</option>
+</ruby>
+
+Note: Only the +option+ tags are returned, you have to wrap this call in a regular HTML +select+ tag.
+
+h5. options_from_collection_for_select
+
+Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the the result of a call to the +value_method+ as the option value and the +text_method+ as the option text.
+
+<ruby>
+# options_from_collection_for_select(collection, value_method, text_method, selected = nil)
+</ruby>
+
+For example, imagine a loop iterating over each person in @project.people to generate an input tag:
+
+<ruby>
+options_from_collection_for_select(@project.people, "id", "name")
+# => <option value="#{person.id}">#{person.name}</option>
+</ruby>
+
+Note: Only the +option+ tags are returned, you have to wrap this call in a regular HTML +select+ tag.
+
+h5. select
+
+Create a select tag and a series of contained option tags for the provided object and method.
+
+Example with @post.person_id => 1:
+
+<ruby>
+select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, { :include_blank => true })
+</ruby>
+
+could become:
+
+<html>
+<select name="post[person_id]">
+ <option value=""></option>
+ <option value="1" selected="selected">David</option>
+ <option value="2">Sam</option>
+ <option value="3">Tobias</option>
+</select>
+</html>
+
+h5. time_zone_options_for_select
+
+Returns a string of option tags for pretty much any time zone in the world.
+
+h5. time_zone_select
+
+Return select and option tags for the given object and method, using +time_zone_options_for_select+ to generate the list of option tags.
+
+<ruby>
+time_zone_select( "user", "time_zone")
+</ruby>
+
+h4. FormTagHelper
+
+Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like FormHelper does. Instead, you provide the names and values manually.
+
+h5. check_box_tag
+
+Creates a check box form input tag.
+
+<ruby>
+check_box_tag 'accept'
+# => <input id="accept" name="accept" type="checkbox" value="1" />
+</ruby>
+
+h5. field_set_tag
+
+Creates a field set for grouping HTML form elements.