aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Bergman <MZBPhoto@gmail.com>2008-09-21 22:49:29 -0400
committerMatthew Bergman <MZBPhoto@gmail.com>2008-09-21 22:49:29 -0400
commitea1eb57f56a4143d575ad8a3df54e063d8cea364 (patch)
treef7d97d3c11104a1c3584c77ac55e396c304f8e15
parent6664177b4459d913943a326fffd5459611852b49 (diff)
parent91871f25f01f6b5d67e7da4aeb6dec0fae7b18fe (diff)
downloadrails-ea1eb57f56a4143d575ad8a3df54e063d8cea364.tar.gz
rails-ea1eb57f56a4143d575ad8a3df54e063d8cea364.tar.bz2
rails-ea1eb57f56a4143d575ad8a3df54e063d8cea364.zip
Merge branch 'master' of git@github.com:lifo/docrails
-rw-r--r--activerecord/lib/active_record/association_preload.rb90
-rwxr-xr-xactiverecord/lib/active_record/associations.rb6
-rwxr-xr-xactiverecord/lib/active_record/base.rb92
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb10
-rw-r--r--activerecord/lib/active_record/validations.rb68
-rw-r--r--activesupport/lib/active_support/base64.rb15
-rw-r--r--activesupport/lib/active_support/core_ext/array/access.rb18
-rw-r--r--activesupport/lib/active_support/core_ext/base64/encoding.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/object/misc.rb52
-rw-r--r--railties/doc/guides/bechmarking and profiling/.DS_Storebin6148 -> 0 bytes
-rw-r--r--railties/doc/guides/bechmarking and profiling/Examples/.DS_Storebin6148 -> 0 bytes
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/Basics.html (renamed from railties/doc/guides/bechmarking and profiling/Basics.html)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/Examples/graph.html (renamed from railties/doc/guides/bechmarking and profiling/Examples/graph.html)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/Images/KGraph.png (renamed from railties/doc/guides/bechmarking and profiling/Images/KGraph.png)bin92342 -> 92342 bytes
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/Images/KList.png (renamed from railties/doc/guides/bechmarking and profiling/Images/KList.png)bin20323 -> 20323 bytes
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/appendix.txt (renamed from railties/doc/guides/bechmarking and profiling/appendix.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/basics.txt (renamed from railties/doc/guides/bechmarking and profiling/basics.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/definitions.txt (renamed from railties/doc/guides/bechmarking and profiling/definitions.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/digging_deeper.txt (renamed from railties/doc/guides/bechmarking and profiling/digging_deeper.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/edge rails features.txt (renamed from railties/doc/guides/bechmarking and profiling/edge rails features.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/gameplan.txt (renamed from railties/doc/guides/bechmarking and profiling/gameplan.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/preamble.html (renamed from railties/doc/guides/bechmarking and profiling/preamble.html)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/preamble.txt (renamed from railties/doc/guides/bechmarking and profiling/preamble.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/rubyprof.txt (renamed from railties/doc/guides/bechmarking and profiling/rubyprof.txt)0
-rw-r--r--railties/doc/guides/benchmarking_and_profiling/statistics.txt (renamed from railties/doc/guides/bechmarking and profiling/statistics.txt)0
-rw-r--r--railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt37
-rw-r--r--railties/doc/guides/index.txt63
-rw-r--r--railties/doc/guides/routing/routing_outside_in.txt68
-rw-r--r--railties/lib/tasks/documentation.rake1
30 files changed, 442 insertions, 89 deletions
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index c60850fc77..cef8cd8647 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -1,14 +1,88 @@
module ActiveRecord
+ # See ActiveRecord::AssociationPreload::ClassMethods for documentation.
module AssociationPreload #:nodoc:
def self.included(base)
base.extend(ClassMethods)
end
+ # Implements the details of eager loading of ActiveRecord associations.
+ # Application developers should not use this module directly.
+ #
+ # ActiveRecord::Base is extended with this module. The source code in
+ # ActiveRecord::Base references methods defined in this module.
+ #
+ # Note that 'eager loading' and 'preloading' are actually the same thing.
+ # However, there are two different eager loading strategies.
+ #
+ # The first one is by using table joins. This was only strategy available
+ # prior to Rails 2.1. Suppose that you have an Author model with columns
+ # 'name' and 'age', and a Book model with columns 'name' and 'sales'. Using
+ # this strategy, ActiveRecord would try to retrieve all data for an author
+ # and all of its books via a single query:
+ #
+ # SELECT * FROM authors
+ # LEFT OUTER JOIN books ON authors.id = books.id
+ # WHERE authors.name = 'Ken Akamatsu'
+ #
+ # However, this could result in many rows that contain redundant data. After
+ # having received the first row, we already have enough data to instantiate
+ # the Author object. In all subsequent rows, only the data for the joined
+ # 'books' table is useful; the joined 'authors' data is just redundant, and
+ # processing this redundant data takes memory and CPU time. The problem
+ # quickly becomes worse and worse as the level of eager loading increases
+ # (i.e. if ActiveRecord is to eager load the associations' assocations as
+ # well).
+ #
+ # The second strategy is to use multiple database queries, one for each
+ # level of association. Since Rails 2.1, this is the default strategy. In
+ # situations where a table join is necessary (e.g. when the +:conditions+
+ # option references an association's column), it will fallback to the table
+ # join strategy.
+ #
+ # See also ActiveRecord::Associations::ClassMethods, which explains eager
+ # loading in a more high-level (application developer-friendly) manner.
module ClassMethods
-
- # Loads the named associations for the activerecord record (or records) given
- # preload_options is passed only one level deep: don't pass to the child associations when associations is a Hash
protected
+
+ # Eager loads the named associations for the given ActiveRecord record(s).
+ #
+ # In this description, 'association name' shall refer to the name passed
+ # to an association creation method. For example, a model that specifies
+ # <tt>belongs_to :author</tt>, <tt>has_many :buyers</tt> has association
+ # names +:author+ and +:buyers+.
+ #
+ # == Parameters
+ # +records+ is an array of ActiveRecord::Base. This array needs not be flat,
+ # i.e. +records+ itself may also contain arrays of records. In any case,
+ # +preload_associations+ will preload the associations all records by
+ # flattening +records+.
+ #
+ # +associations+ specifies one or more associations that you want to
+ # preload. It may be:
+ # - a Symbol or a String which specifies a single association name. For
+ # example, specifiying +:books+ allows this method to preload all books
+ # for an Author.
+ # - an Array which specifies multiple association names. This array
+ # is processed recursively. For example, specifying <tt>[:avatar, :books]</tt>
+ # allows this method to preload an author's avatar as well as all of his
+ # books.
+ # - a Hash which specifies multiple association names, as well as
+ # association names for the to-be-preloaded association objects. For
+ # example, specifying <tt>{ :author => :avatar }</tt> will preload a
+ # book's author, as well as that author's avatar.
+ #
+ # +:associations+ has the same format as the +:include+ option for
+ # <tt>ActiveRecord::Base.find</tt>. So +associations+ could look like this:
+ #
+ # :books
+ # [ :books, :author ]
+ # { :author => :avatar }
+ # [ :books, { :author => :avatar } ]
+ #
+ # +preload_options+ contains options that will be passed to ActiveRecord#find
+ # (which is called under the hood for preloading records). But it is passed
+ # only one level deep in the +associations+ argument, i.e. it's not passed
+ # to the child associations when +associations+ is a Hash.
def preload_associations(records, associations, preload_options={})
records = [records].flatten.compact.uniq
return if records.empty?
@@ -30,6 +104,8 @@ module ActiveRecord
private
+ # Preloads a specific named association for the given records. This is
+ # called by +preload_associations+ as its base case.
def preload_one_association(records, association, preload_options={})
class_to_reflection = {}
# Not all records have the same class, so group then preload
@@ -37,6 +113,10 @@ module ActiveRecord
# unnecessarily
records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records|
raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection
+
+ # 'reflection.macro' can return 'belongs_to', 'has_many', etc. Thus,
+ # the following could call 'preload_belongs_to_association',
+ # 'preload_has_many_association', etc.
send("preload_#{reflection.macro}_association", records, reflection, preload_options)
end
end
@@ -77,6 +157,10 @@ module ActiveRecord
end
end
+ # Given a collection of ActiveRecord objects, constructs a Hash which maps
+ # the objects' IDs to the relevant objects. Returns a 2-tuple
+ # <tt>(id_to_record_map, ids)</tt> where +id_to_record_map+ is the Hash,
+ # and +ids+ is an Array of record IDs.
def construct_id_map(records)
id_to_record_map = {}
ids = []
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 5d91315aad..33457822ff 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1452,6 +1452,8 @@ module ActiveRecord
end
end
+ # Creates before_destroy callback methods that nullify, delete or destroy
+ # has_one associated objects, according to the defined :dependent rule.
def configure_dependency_for_has_one(reflection)
if reflection.options.include?(:dependent)
case reflection.options[:dependent]
@@ -1465,6 +1467,10 @@ module ActiveRecord
when :delete
method_name = "has_one_dependent_delete_for_#{reflection.name}".to_sym
define_method(method_name) do
+ # Retrieve the associated object and delete it. The retrieval
+ # is necessary because there may be multiple associated objects
+ # with foreign keys pointing to this object, and we only want
+ # to delete the correct one, not all of them.
association = send(reflection.name)
association.class.delete(association.id) unless association.nil?
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 556f9f115b..c0c9b8a9b3 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -512,7 +512,7 @@ module ActiveRecord #:nodoc:
#
# All approaches accept an options hash as their last parameter.
#
- # ==== Attributes
+ # ==== Parameters
#
# * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or <tt>[ "user_name = ?", username ]</tt>. See conditions in the intro.
# * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
@@ -697,7 +697,7 @@ module ActiveRecord #:nodoc:
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
# The resulting object is returned whether the object was saved successfully to the database or not.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +id+ - This should be the id or an array of ids to be updated.
# * +attributes+ - This should be a Hash of attributes to be set on the object, or an array of Hashes.
@@ -725,9 +725,10 @@ module ActiveRecord #:nodoc:
# is executed on the database which means that no callbacks are fired off running this. This is an efficient method
# of deleting records that don't need cleaning up after or other actions to be taken.
#
- # Objects are _not_ instantiated with this method.
+ # Objects are _not_ instantiated with this method, and so +:dependent+ rules
+ # defined on associations are not honered.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +id+ - Can be either an Integer or an Array of Integers.
#
@@ -750,7 +751,7 @@ module ActiveRecord #:nodoc:
# This essentially finds the object (or multiple objects) with the given id, creates a new object
# from the attributes, and then calls destroy on it.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +id+ - Can be either an Integer or an Array of Integers.
#
@@ -774,7 +775,7 @@ module ActiveRecord #:nodoc:
# also be supplied. This method constructs a single SQL UPDATE statement and sends it straight to the
# database. It does not instantiate the involved models and it does not trigger Active Record callbacks.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +updates+ - A string of column and value pairs that will be set on any records that match conditions.
# What goes into the SET clause.
@@ -820,34 +821,39 @@ module ActiveRecord #:nodoc:
# many records. If you want to simply delete records without worrying about dependent associations or
# callbacks, use the much faster +delete_all+ method instead.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +conditions+ - Conditions are specified the same way as with +find+ method.
#
# ==== Example
#
- # Person.destroy_all "last_login < '2004-04-04'"
+ # Person.destroy_all("last_login < '2004-04-04'")
#
# This loads and destroys each person one by one, including its dependent associations and before_ and
# after_destroy callbacks.
+ #
+ # +conditions+ can be anything that +find+ also accepts:
+ #
+ # Person.destroy_all(:last_login => 6.hours.ago)
def destroy_all(conditions = nil)
find(:all, :conditions => conditions).each { |object| object.destroy }
end
# Deletes the records matching +conditions+ without instantiating the records first, and hence not
# calling the +destroy+ method nor invoking callbacks. This is a single SQL DELETE statement that
- # goes straight to the database, much more efficient than +destroy_all+. Careful with relations
- # though, in particular <tt>:dependent</tt> is not taken into account.
+ # goes straight to the database, much more efficient than +destroy_all+. Be careful with relations
+ # though, in particular <tt>:dependent</tt> rules defined on associations are not honored.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +conditions+ - Conditions are specified the same way as with +find+ method.
#
# ==== Example
#
- # Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"
+ # Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
+ # Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
#
- # This deletes the affected posts all at once with a single DELETE statement. If you need to destroy dependent
+ # Both calls delete the affected posts all at once with a single DELETE statement. If you need to destroy dependent
# associations or call your <tt>before_*</tt> or +after_destroy+ callbacks, use the +destroy_all+ method instead.
def delete_all(conditions = nil)
sql = "DELETE FROM #{quoted_table_name} "
@@ -859,7 +865,7 @@ module ActiveRecord #:nodoc:
# The use of this method should be restricted to complicated SQL queries that can't be executed
# using the ActiveRecord::Calculations class methods. Look into those before using this.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +sql+ - An SQL statement which should return a count query from the database, see the example below.
#
@@ -877,7 +883,7 @@ module ActiveRecord #:nodoc:
# with the given ID, altering the given hash of counters by the amount
# given by the corresponding value:
#
- # ==== Attributes
+ # ==== Parameters
#
# * +id+ - The id of the object you wish to update a counter on.
# * +counters+ - An Array of Hashes containing the names of the fields
@@ -907,7 +913,7 @@ module ActiveRecord #:nodoc:
# For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is
# shown it would have to run an SQL query to find how many posts and comments there are.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +counter_name+ - The name of the field that should be incremented.
# * +id+ - The id of the object that should be incremented.
@@ -924,7 +930,7 @@ module ActiveRecord #:nodoc:
#
# This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +counter_name+ - The name of the field that should be decremented.
# * +id+ - The id of the object that should be decremented.
@@ -1019,7 +1025,7 @@ module ActiveRecord #:nodoc:
# The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that
# class on retrieval or SerializationTypeMismatch will be raised.
#
- # ==== Attributes
+ # ==== Parameters
#
# * +attr_name+ - The field name that should be serialized.
# * +class_name+ - Optional, class name that the object type should be equal to.
@@ -1927,6 +1933,9 @@ module ActiveRecord #:nodoc:
# end
# end
# end
+ #
+ # *Note*: the +:find+ scope also has effect on update and deletion methods,
+ # like +update_all+ and +delete_all+.
def with_scope(method_scoping = {}, action = :merge, &block)
method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping)
@@ -2274,7 +2283,28 @@ module ActiveRecord #:nodoc:
end
- # Enables Active Record objects to be used as URL parameters in Action Pack automatically.
+ # Returns a String, which Action Pack uses for constructing an URL to this
+ # object. The default implementation returns this record's id as a String,
+ # or nil if this record's unsaved.
+ #
+ # For example, suppose that you have a Users model, and that you have a
+ # <tt>map.resources :users</tt> route. Normally, +users_path+ will
+ # construct an URI with the user object's 'id' in it:
+ #
+ # user = User.find_by_name('Phusion')
+ # user_path(path) # => "/users/1"
+ #
+ # You can override +to_param+ in your model to make +users_path+ construct
+ # an URI using the user's name instead of the user's id:
+ #
+ # class User < ActiveRecord::Base
+ # def to_param # overridden
+ # name
+ # end
+ # end
+ #
+ # user = User.find_by_name('Phusion')
+ # user_path(path) # => "/users/Phusion"
def to_param
# We can't use alias_method here, because method 'id' optimizes itself on the fly.
(id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes
@@ -2356,6 +2386,9 @@ module ActiveRecord #:nodoc:
# Deletes the record in the database and freezes this instance to reflect that no changes should
# be made (since they can't be persisted).
+ #
+ # In addition to deleting this record, any defined +before_delete+ and +after_delete+
+ # callbacks are run, and +:dependent+ rules defined on associations are run.
def destroy
unless new_record?
connection.delete <<-end_sql, "#{self.class.name} Destroy"
@@ -2493,10 +2526,25 @@ module ActiveRecord #:nodoc:
end
# Allows you to set all the attributes at once by passing in a hash with keys
- # matching the attribute names (which again matches the column names). Sensitive attributes can be protected
- # from this form of mass-assignment by using the +attr_protected+ macro. Or you can alternatively
- # specify which attributes *can* be accessed with the +attr_accessible+ macro. Then all the
+ # matching the attribute names (which again matches the column names).
+ #
+ # If +guard_protected_attributes+ is true (the default), then sensitive
+ # attributes can be protected from this form of mass-assignment by using
+ # the +attr_protected+ macro. Or you can alternatively specify which
+ # attributes *can* be accessed with the +attr_accessible+ macro. Then all the
# attributes not included in that won't be allowed to be mass-assigned.
+ #
+ # class User < ActiveRecord::Base
+ # attr_protected :is_admin
+ # end
+ #
+ # user = User.new
+ # user.attributes = { :username => 'Phusion', :is_admin => true }
+ # user.username # => "Phusion"
+ # user.is_admin? # => false
+ #
+ # user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
+ # user.is_admin? # => true
def attributes=(new_attributes, guard_protected_attributes = true)
return if new_attributes.nil?
attributes = new_attributes.dup
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 8fc89de22b..10dc1a81f3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -98,8 +98,14 @@ module ActiveRecord
add_limit_offset!(sql, options) if options
end
- # Appends +LIMIT+ and +OFFSET+ options to an SQL statement.
+ # Appends +LIMIT+ and +OFFSET+ options to an SQL statement, or some SQL
+ # fragment that has the same semantics as LIMIT and OFFSET.
+ #
+ # +options+ must be a Hash which contains a +:limit+ option (required)
+ # and an +:offset+ option (optional).
+ #
# This method *modifies* the +sql+ parameter.
+ #
# ===== Examples
# add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})
# generates
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index bececf82a0..c29c1562b4 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -31,19 +31,25 @@ module ActiveRecord
# See the concrete implementation for details on the expected parameter values.
def columns(table_name, name = nil) end
- # Creates a new table
+ # Creates a new table with the name +table_name+. +table_name+ may either
+ # be a String or a Symbol.
+ #
# There are two ways to work with +create_table+. You can use the block
# form or the regular form, like this:
#
# === Block form
- # # create_table() yields a TableDefinition instance
+ # # create_table() passes a TableDefinition object to the block.
+ # # This form will not only create the table, but also columns for the
+ # # table.
# create_table(:suppliers) do |t|
# t.column :name, :string, :limit => 60
# # Other fields here
# end
#
# === Regular form
+ # # Creates a table called 'suppliers' with no columns.
# create_table(:suppliers)
+ # # Add a column to 'suppliers'.
# add_column(:suppliers, :name, :string, {:limit => 60})
#
# The +options+ hash can include the following keys:
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index 518b59e433..73d9b36fc2 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -625,10 +625,6 @@ module ActiveRecord
# When the record is created, a check is performed to make sure that no record exists in the database with the given value for the specified
# attribute (that maps to a column). When the record is updated, the same check is made but disregarding the record itself.
#
- # Because this check is performed outside the database there is still a chance that duplicate values
- # will be inserted in two parallel transactions. To guarantee against this you should create a
- # unique index on the field. See +add_index+ for more information.
- #
# Configuration options:
# * <tt>:message</tt> - Specifies a custom error message (default is: "has already been taken").
# * <tt>:scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint.
@@ -641,6 +637,70 @@ module ActiveRecord
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
+ #
+ # === Concurrency and integrity
+ #
+ # Using this validation method in conjunction with ActiveRecord::Base#save
+ # does not guarantee the absence of duplicate record insertions, because
+ # uniqueness checks on the application level are inherently prone to racing
+ # conditions. For example, suppose that two users try to post a Comment at
+ # the same time, and a Comment's title must be unique. At the database-level,
+ # the actions performed by these users could be interleaved in the following manner:
+ #
+ # User 1 | User 2
+ # ------------------------------------+--------------------------------------
+ # # User 1 checks whether there's |
+ # # already a comment with the title |
+ # # 'My Post'. This is not the case. |
+ # SELECT * FROM comments |
+ # WHERE title = 'My Post' |
+ # |
+ # | # User 2 does the same thing and also
+ # | # infers that his title is unique.
+ # | SELECT * FROM comments
+ # | WHERE title = 'My Post'
+ # |
+ # # User 1 inserts his comment. |
+ # INSERT INTO comments |
+ # (title, content) VALUES |
+ # ('My Post', 'hi!') |
+ # |
+ # | # User 2 does the same thing.
+ # | INSERT INTO comments
+ # | (title, content) VALUES
+ # | ('My Post', 'hello!')
+ # |
+ # | # ^^^^^^
+ # | # Boom! We now have a duplicate
+ # | # title!
+ #
+ # This could even happen if you use transactions with the 'serializable'
+ # isolation level. There are several ways to get around this problem:
+ # - By locking the database table before validating, and unlocking it after
+ # saving. However, table locking is very expensive, and thus not
+ # recommended.
+ # - By locking a lock file before validating, and unlocking it after saving.
+ # This does not work if you've scaled your Rails application across
+ # multiple web servers (because they cannot share lock files, or cannot
+ # do that efficiently), and thus not recommended.
+ # - Creating a unique index on the field, by using
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#add_index. In the
+ # rare case that a racing condition occurs, the database will guarantee
+ # the field's uniqueness.
+ #
+ # When the database catches such a duplicate insertion,
+ # ActiveRecord::Base#save will raise an ActiveRecord::StatementInvalid
+ # exception. You can either choose to let this error propagate (which
+ # will result in the default Rails exception page being shown), or you
+ # can catch it and restart the transaction (e.g. by telling the user
+ # that the title already exists, and asking him to re-enter the title).
+ # This technique is also known as optimistic concurrency control:
+ # http://en.wikipedia.org/wiki/Optimistic_concurrency_control
+ #
+ # Active Record currently provides no way to distinguish unique
+ # index constraint errors from other types of database errors, so you
+ # will have to parse the (database-specific) exception message to detect
+ # such a case.
def validates_uniqueness_of(*attr_names)
configuration = { :case_sensitive => true }
configuration.update(attr_names.extract_options!)
diff --git a/activesupport/lib/active_support/base64.rb b/activesupport/lib/active_support/base64.rb
index 602eef06b2..acb8e5a967 100644
--- a/activesupport/lib/active_support/base64.rb
+++ b/activesupport/lib/active_support/base64.rb
@@ -7,13 +7,24 @@ module ActiveSupport
if defined? ::Base64
Base64 = ::Base64
else
- # Ruby 1.9 doesn't provide base64, so we wrap this here
+ # Base64 provides utility methods for encoding and de-coding binary data
+ # using a base 64 representation. A base 64 representation of binary data
+ # consists entirely of printable US-ASCII characters. The Base64 module
+ # is included in Ruby 1.8, but has been removed in Ruby 1.9.
module Base64
-
+ # Encodes a string to its base 64 representation. Each 60 characters of
+ # output is separated by a newline character.
+ #
+ # ActiveSupport::Base64.encode64("Original unencoded string")
+ # # => "T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==\n"
def self.encode64(data)
[data].pack("m")
end
+ # Decodes a base 64 encoded string to its original representation.
+ #
+ # ActiveSupport::Base64.decode64("T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==")
+ # # => "Original unencoded string"
def self.decode64(data)
data.unpack("m").first
end
diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb
index 779ca40aea..a3b2a54c7d 100644
--- a/activesupport/lib/active_support/core_ext/array/access.rb
+++ b/activesupport/lib/active_support/core_ext/array/access.rb
@@ -23,47 +23,47 @@ module ActiveSupport #:nodoc:
self[0..position]
end
- # Equals to <tt>self[1]</tt>.
+ # Equal to <tt>self[1]</tt>.
def second
self[1]
end
- # Equals to <tt>self[2]</tt>.
+ # Equal to <tt>self[2]</tt>.
def third
self[2]
end
- # Equals to <tt>self[3]</tt>.
+ # Equal to <tt>self[3]</tt>.
def fourth
self[3]
end
- # Equals to <tt>self[4]</tt>.
+ # Equal to <tt>self[4]</tt>.
def fifth
self[4]
end
- # Equals to <tt>self[5]</tt>.
+ # Equal to <tt>self[5]</tt>.
def sixth
self[5]
end
- # Equals to <tt>self[6]</tt>.
+ # Equal to <tt>self[6]</tt>.
def seventh
self[6]
end
- # Equals to <tt>self[7]</tt>.
+ # Equal to <tt>self[7]</tt>.
def eighth
self[7]
end
- # Equals to <tt>self[8]</tt>.
+ # Equal to <tt>self[8]</tt>.
def ninth
self[8]
end
- # Equals to <tt>self[9]</tt>.
+ # Equal to <tt>self[9]</tt>.
def tenth
self[9]
end
diff --git a/activesupport/lib/active_support/core_ext/base64/encoding.rb b/activesupport/lib/active_support/core_ext/base64/encoding.rb
index 1a40da8785..a9656c138e 100644
--- a/activesupport/lib/active_support/core_ext/base64/encoding.rb
+++ b/activesupport/lib/active_support/core_ext/base64/encoding.rb
@@ -4,6 +4,9 @@ module ActiveSupport #:nodoc:
module Encoding
# Encodes the value as base64 without the newline breaks. This makes the base64 encoding readily usable as URL parameters
# or memcache keys without further processing.
+ #
+ # ActiveSupport::Base64.encode64s("Original unencoded string")
+ # # => "T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw=="
def encode64s(value)
encode64(value).gsub(/\n/, '')
end
diff --git a/activesupport/lib/active_support/core_ext/object/misc.rb b/activesupport/lib/active_support/core_ext/object/misc.rb
index 06a7d05702..cd0a04d32a 100644
--- a/activesupport/lib/active_support/core_ext/object/misc.rb
+++ b/activesupport/lib/active_support/core_ext/object/misc.rb
@@ -1,30 +1,50 @@
class Object
- # A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
+ # Returns +value+ after yielding +value+ to the block. This simplifies the
+ # process of constructing an object, performing work on the object, and then
+ # returning the object from a method. It is a Ruby-ized realization of the K
+ # combinator, courtesy of Mikael Brockman.
#
- # def foo
- # returning values = [] do
- # values << 'bar'
- # values << 'baz'
- # end
- # end
+ # ==== Examples
#
- # foo # => ['bar', 'baz']
+ # # Without returning
+ # def foo
+ # values = []
+ # values << "bar"
+ # values << "baz"
+ # return values
+ # end
#
- # def foo
- # returning [] do |values|
- # values << 'bar'
- # values << 'baz'
- # end
- # end
+ # foo # => ['bar', 'baz']
#
- # foo # => ['bar', 'baz']
+ # # returning with a local variable
+ # def foo
+ # returning values = [] do
+ # values << 'bar'
+ # values << 'baz'
+ # end
+ # end
#
+ # foo # => ['bar', 'baz']
+ #
+ # # returning with a block argument
+ # def foo
+ # returning [] do |values|
+ # values << 'bar'
+ # values << 'baz'
+ # end
+ # end
+ #
+ # foo # => ['bar', 'baz']
def returning(value)
yield(value)
value
end
- # An elegant way to refactor out common options
+ # An elegant way to factor duplication out of options passed to a series of
+ # method calls. Each method called in the block, with the block variable as
+ # the receiver, will have its options merged with the default +options+ hash
+ # provided. Each method called on the block variable must take an options
+ # hash as its final argument.
#
# with_options :order => 'created_at', :class_name => 'Comment' do |post|
# post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
diff --git a/railties/doc/guides/bechmarking and profiling/.DS_Store b/railties/doc/guides/bechmarking and profiling/.DS_Store
deleted file mode 100644
index d933a198e6..0000000000
--- a/railties/doc/guides/bechmarking and profiling/.DS_Store
+++ /dev/null
Binary files differ
diff --git a/railties/doc/guides/bechmarking and profiling/Examples/.DS_Store b/railties/doc/guides/bechmarking and profiling/Examples/.DS_Store
deleted file mode 100644
index 5008ddfcf5..0000000000
--- a/railties/doc/guides/bechmarking and profiling/Examples/.DS_Store
+++ /dev/null
Binary files differ
diff --git a/railties/doc/guides/bechmarking and profiling/Basics.html b/railties/doc/guides/benchmarking_and_profiling/Basics.html
index 5cf3939fd6..5cf3939fd6 100644
--- a/railties/doc/guides/bechmarking and profiling/Basics.html
+++ b/railties/doc/guides/benchmarking_and_profiling/Basics.html
diff --git a/railties/doc/guides/bechmarking and profiling/Examples/graph.html b/railties/doc/guides/benchmarking_and_profiling/Examples/graph.html
index 807a405284..807a405284 100644
--- a/railties/doc/guides/bechmarking and profiling/Examples/graph.html
+++ b/railties/doc/guides/benchmarking_and_profiling/Examples/graph.html
diff --git a/railties/doc/guides/bechmarking and profiling/Images/KGraph.png b/railties/doc/guides/benchmarking_and_profiling/Images/KGraph.png
index fecdcd0531..fecdcd0531 100644
--- a/railties/doc/guides/bechmarking and profiling/Images/KGraph.png
+++ b/railties/doc/guides/benchmarking_and_profiling/Images/KGraph.png
Binary files differ
diff --git a/railties/doc/guides/bechmarking and profiling/Images/KList.png b/railties/doc/guides/benchmarking_and_profiling/Images/KList.png
index 57b3568832..57b3568832 100644
--- a/railties/doc/guides/bechmarking and profiling/Images/KList.png
+++ b/railties/doc/guides/benchmarking_and_profiling/Images/KList.png
Binary files differ
diff --git a/railties/doc/guides/bechmarking and profiling/appendix.txt b/railties/doc/guides/benchmarking_and_profiling/appendix.txt
index edda9607ed..edda9607ed 100644
--- a/railties/doc/guides/bechmarking and profiling/appendix.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/appendix.txt
diff --git a/railties/doc/guides/bechmarking and profiling/basics.txt b/railties/doc/guides/benchmarking_and_profiling/basics.txt
index 24174efc7e..24174efc7e 100644
--- a/railties/doc/guides/bechmarking and profiling/basics.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/basics.txt
diff --git a/railties/doc/guides/bechmarking and profiling/definitions.txt b/railties/doc/guides/benchmarking_and_profiling/definitions.txt
index 3ba3cc41e0..3ba3cc41e0 100644
--- a/railties/doc/guides/bechmarking and profiling/definitions.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/definitions.txt
diff --git a/railties/doc/guides/bechmarking and profiling/digging_deeper.txt b/railties/doc/guides/benchmarking_and_profiling/digging_deeper.txt
index 73a72e1264..73a72e1264 100644
--- a/railties/doc/guides/bechmarking and profiling/digging_deeper.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/digging_deeper.txt
diff --git a/railties/doc/guides/bechmarking and profiling/edge rails features.txt b/railties/doc/guides/benchmarking_and_profiling/edge rails features.txt
index ede1c5831e..ede1c5831e 100644
--- a/railties/doc/guides/bechmarking and profiling/edge rails features.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/edge rails features.txt
diff --git a/railties/doc/guides/bechmarking and profiling/gameplan.txt b/railties/doc/guides/benchmarking_and_profiling/gameplan.txt
index 578a70ebaa..578a70ebaa 100644
--- a/railties/doc/guides/bechmarking and profiling/gameplan.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/gameplan.txt
diff --git a/railties/doc/guides/bechmarking and profiling/preamble.html b/railties/doc/guides/benchmarking_and_profiling/preamble.html
index b52b8a7e74..b52b8a7e74 100644
--- a/railties/doc/guides/bechmarking and profiling/preamble.html
+++ b/railties/doc/guides/benchmarking_and_profiling/preamble.html
diff --git a/railties/doc/guides/bechmarking and profiling/preamble.txt b/railties/doc/guides/benchmarking_and_profiling/preamble.txt
index bba8217793..bba8217793 100644
--- a/railties/doc/guides/bechmarking and profiling/preamble.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/preamble.txt
diff --git a/railties/doc/guides/bechmarking and profiling/rubyprof.txt b/railties/doc/guides/benchmarking_and_profiling/rubyprof.txt
index edf036d13e..edf036d13e 100644
--- a/railties/doc/guides/bechmarking and profiling/rubyprof.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/rubyprof.txt
diff --git a/railties/doc/guides/bechmarking and profiling/statistics.txt b/railties/doc/guides/benchmarking_and_profiling/statistics.txt
index c3b4464d4b..c3b4464d4b 100644
--- a/railties/doc/guides/bechmarking and profiling/statistics.txt
+++ b/railties/doc/guides/benchmarking_and_profiling/statistics.txt
diff --git a/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt b/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt
index 2805e5629d..3259ef8a45 100644
--- a/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt
+++ b/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt
@@ -317,7 +317,42 @@ This time, we're setting `@post` to a single record in the database that is sear
==== New & Create
-Description of new and create actions
+In your controller, you'll see the `new` and `create` actions, which are used together to create a new record. Our `new` action simply instantiates a new Post object without any parameters:
+
+-----------------------------------------
+def new
+ @post = Post.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @post }
+ end
+end
+----------------------------------------
+
+Our `create` action, on the other hand, instantiates a new Post object while setting its attributes to the parameters that we specify in our form. It then uses a `flash[:notice]` to inform the user of the status of the action. If the Post is saved successfully, the action will redirect to the `show` action containing our new Post simply by calling the simple `redirect_to(@post)`.
+
+.The Flash
+**************************************************************************************************************
+Rails provides 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 our `create` example, the user never actually sees any page rendered during the Post creation process, because it immediately redirects to the new Post as soon as the record is saved. The Flash allows us to carry over a message to the next action, so once the user is redirected back to the `show` action, they are presented with a message saying "Post was successfully created."
+**************************************************************************************************************
+
+----------------------------------------
+def create
+ @post = Post.new(params[:post])
+
+ 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 }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @post.errors, :status => :unprocessable_entity }
+ end
+ end
+end
+---------------------------------------
==== Edit & Update
diff --git a/railties/doc/guides/index.txt b/railties/doc/guides/index.txt
index 45002f874a..402037a7d1 100644
--- a/railties/doc/guides/index.txt
+++ b/railties/doc/guides/index.txt
@@ -3,28 +3,60 @@ Ruby on Rails guides
WARNING: This page is the result of ongoing http://hackfest.rubyonrails.org/guide[Rails Guides hackfest] and a work in progress.
-.link:getting_started_with_rails/getting_started_with_rails.html[Getting Started with Rails]
+++++++++++++++++++++++++++++++++++++++
+<h2>Finished Guides</h2>
+++++++++++++++++++++++++++++++++++++++
+
+These guides are complete and the authors are listed link:authors.html[here].
+
+.link:migrations/migrations.html[Rails Database Migrations]
***********************************************************
TODO: Insert some description here.
***********************************************************
-.link:activerecord/association_basics.html[Active Record Associations]
+.link:routing/routing_outside_in.html[Rails Routing from the Outside In]
***********************************************************
-Introduction to Active Record associations.
+This guide covers the user-facing features of Rails routing. If you want to
+understand how to use routing in your own Rails applications, start here.
***********************************************************
-.link:migrations/migrations.html[Rails Database Migrations]
+++++++++++++++++++++++++++++++++++++++
+<h2>Guides in progress</h2>
+++++++++++++++++++++++++++++++++++++++
+
+These guides are currently being worked on. While they still might be useful to you, you could always help by reviewing them and posting your
+findings at the respective Lighthouse ticket.
+
+.link:debugging/debugging_rails_applications.html[Debugging Rails Applications]
***********************************************************
-TODO: Insert some description here.
+link:http://rails.lighthouseapp.com/projects/16213/tickets/5[Lighthouse Ticket]
+
+This guide describes how to debug Rails applications. It covers the different
+ways of achieving this and how to understand what is happening "behind the scenes"
+of your code.
+***********************************************************
+
+.link:getting_started_with_rails/getting_started_with_rails.html[Getting Started with Rails]
+***********************************************************
+link:http://rails.lighthouseapp.com/projects/16213/tickets/2[Lighthouse Ticket]
+***********************************************************
+
+.link:activerecord/association_basics.html[Active Record Associations]
+***********************************************************
+link:http://rails.lighthouseapp.com/projects/16213/tickets/11[Lighthouse Ticket]
***********************************************************
.link:forms/form_helpers.html[Action View Form Helpers]
***********************************************************
+link:http://rails.lighthouseapp.com/projects/16213/tickets/1[Lighthouse Ticket]
+
Guide to using built in Form helpers.
***********************************************************
.link:testing_rails_applications/testing_rails_applications.html[Testing Rails Applications]
***********************************************************
+link:http://rails.lighthouseapp.com/projects/16213/tickets/8[Lighthouse Ticket]
+
This is a rather comprehensive guide to doing both unit and functional tests
in Rails. It covers everything from ``What is a test?'' to the testing APIs.
Enjoy.
@@ -32,29 +64,20 @@ Enjoy.
.link:securing_rails_applications/security.html[Securing Rails Applications]
***********************************************************
+link:http://rails.lighthouseapp.com/projects/16213/tickets/7[Lighthouse Ticket]
+
This manual describes common security problems in web applications and how to
avoid them with Rails.
***********************************************************
-.link:routing/routing_outside_in.html[Rails Routing from the Outside In]
-***********************************************************
-This guide covers the user-facing features of Rails routing. If you want to
-understand how to use routing in your own Rails applications, start here.
+.link:caching/caching_with_rails.html[Rails Caching]
***********************************************************
+link:http://rails.lighthouseapp.com/projects/16213/tickets/10[Lighthouse Ticket]
-.link:debugging/debugging_rails_applications.html[Debugging Rails Applications]
-***********************************************************
-This guide describes how to debug Rails applications. It covers the different
-ways of achieving this and how to understand what is happening "behind the scenes"
-of your code.
+TODO: Insert some description here.
***********************************************************
.link:creating_plugins/creating_plugins.html[The Basics of Creating Rails Plugins]
***********************************************************
-TODO: Insert some description here.
+TODO: Insert some description here. No Lighthouse ticket.
***********************************************************
-
-.link:caching/caching_with_rails.html[Rails Caching]
-***********************************************************
-TODO: Insert some description here.
-*********************************************************** \ No newline at end of file
diff --git a/railties/doc/guides/routing/routing_outside_in.txt b/railties/doc/guides/routing/routing_outside_in.txt
index 2e48ca59b7..29b69ab47d 100644
--- a/railties/doc/guides/routing/routing_outside_in.txt
+++ b/railties/doc/guides/routing/routing_outside_in.txt
@@ -168,6 +168,24 @@ photos_url # => "http://www.example.com/photos"
photos_path # => "/photos"
-------------------------------------------------------
+=== 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+:
+
+[source, ruby]
+-------------------------------------------------------
+map.resources :photos, :books, :videos
+-------------------------------------------------------
+
+This has exactly the same effect as
+
+[source, ruby]
+-------------------------------------------------------
+map.resources :photos
+map.resources :books
+map.resources :videos
+-------------------------------------------------------
+
=== 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
@@ -379,11 +397,11 @@ HTTP verb URL controller action used for
--------------------------------------------------------------------------------------------
GET /magazines/1/ads Ads index display a list of all ads for a specific magazine
GET /magazines/1/ads/new Ads new return an HTML form for creating a new ad belonging to a specific magazine
-POST /magazines/1/ads Ads create create a new photo belonging to a specific magazine
-GET /magazines/1/ads/1 Ads show display a specific photo belonging to a specific magazine
-GET /magazines/1/ads/1/edit Ads edit return an HTML form for editing a photo belonging to a specific magazine
-PUT /magazines/1/ads/1 Ads update update a specific photo belonging to a specific magazine
-DELETE /magazines/1/ads/1 Ads destroy delete a specific photo belonging to a specific magazine
+POST /magazines/1/ads Ads create create a new ad belonging to a specific magazine
+GET /magazines/1/ads/1 Ads show display a specific ad belonging to a specific magazine
+GET /magazines/1/ads/1/edit Ads edit return an HTML form for editing an ad belonging to a specific magazine
+PUT /magazines/1/ads/1 Ads update update a specific ad belonging to a specific magazine
+DELETE /magazines/1/ads/1 Ads destroy delete a specific ad belonging to a specific magazine
--------------------------------------------------------------------------------------------
This will also create routing helpers such as +magazine_ads_url+ and +magazine_edit_ad_path+.
@@ -499,6 +517,29 @@ If you like, you can combine shallow nesting with the +:has_one+ and +:has_many+
map.resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
-------------------------------------------------------
+=== 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:
+
+[source, ruby]
+-------------------------------------------------------
+map.resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
+map.resources :tags, :path_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
+map.resources :ratings, :path_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
+-------------------------------------------------------
+
+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:
+
+[source, ruby]
+-------------------------------------------------------
+map.namespace(:admin) do |admin|
+ admin.resources :photos,
+ :has_many => { :tags, :ratings}
+end
+-------------------------------------------------------
+
+As you can see, the namespaced version is much more succinct than the one that spells everything out - but it still creates the same routes. For example, you'll get +admin_photos_url+ that expects to find an +Admin::PhotosController+ and that matches +admin/photos+, and +admin_photos_ratings+path+ that matches +/admin/photos/_photo_id_/ratings+, expecting to use +Admin::RatingsController+.
+
=== Adding More RESTful Actions
You are not limited to the seven routes that RESTful routing creates by default. If you like, you may add additional member routes (those which apply to a single instance of the resource), additional new routes (those that apply to creating a new resource), or additional collection routes (those which apply to the collection of resources as a whole).
@@ -574,7 +615,7 @@ You can set up as many wildcard symbols within a regular route as you like. Anyt
[source, ruby]
-------------------------------------------------------
-map.connect ':controller/:action/:id/:userid:'
+map.connect ':controller/:action/:id/:user_id'
-------------------------------------------------------
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.
@@ -585,7 +626,7 @@ You can specify static text when creating a route. In this case, the static text
[source, ruby]
-------------------------------------------------------
-map.connect ':controller/:action/:id/with_user/:userid:'
+map.connect ':controller/:action/:id/with_user/:user_id'
-------------------------------------------------------
This route would respond to URLs such as +/photos/show/1/with_user/2+.
@@ -612,6 +653,15 @@ map.connect 'photo/:id', :controller => 'photos', :action => 'show'
With this route, an incoming URL of +/photos/12+ would be dispatched to the +show+ action within the +Photos+ controller.
+You an 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:
+
+[source, ruby]
+-------------------------------------------------------
+map.connect 'photo/:id', :controller => 'photos', :action => 'show', :defaults => { :format => 'jpg' }
+-------------------------------------------------------
+
+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+.
+
=== Named Routes
Regular routes need not use the +connect+ method. You can use any other name here to create a _named route_. For example,
@@ -655,7 +705,7 @@ As with conditions in RESTful routes, you can specify +:get+, +:post+, +:put+, +
=== Route Globbing
-Route globbing is a way to specify that a particular parameter (which must be the last parameter in the route) should engulf all the remaining parts of a route. For example
+Route globbing is a way to specify that a particular parameter (which must be the last parameter in the route) should be matched to all the remaining parts of a route. For example
[source, ruby]
-------------------------------------------------------
@@ -690,7 +740,7 @@ For instance, consider the second of the default routes in the boilerplate +rout
map.connect ':controller/:action/:id.:format'
-------------------------------------------------------
-This route matches requests such as +/photo/new/1.xml+ or +/photo/show/2.rss+. Within the appropriate action code, you can issue different responses depending on the requested format:
+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:
[source, ruby]
-------------------------------------------------------
diff --git a/railties/lib/tasks/documentation.rake b/railties/lib/tasks/documentation.rake
index 4ef838626a..b20b58ba24 100644
--- a/railties/lib/tasks/documentation.rake
+++ b/railties/lib/tasks/documentation.rake
@@ -55,6 +55,7 @@ namespace :doc do
namespace :plugins do
# Define doc tasks for each plugin
plugins.each do |plugin|
+ desc "Generate documentation for the #{plugin} plugin"
task(plugin => :environment) do
plugin_base = "vendor/plugins/#{plugin}"
options = []