aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Webers <heikowebers@gmx.net>2008-09-17 16:59:43 +0200
committerHeiko Webers <heikowebers@gmx.net>2008-09-17 16:59:43 +0200
commitf7056c5ce8ff94c15f06556e42e0591efc3d2d98 (patch)
tree219ed664ce4fa75ff3e3bbc8cbae7b949d9c795b
parent3642a8f5cc9ebcce3cac3ef94885d5068dbd9503 (diff)
parentf261cd2a94fc128f37f85e86326868341cbfdf3d (diff)
downloadrails-f7056c5ce8ff94c15f06556e42e0591efc3d2d98.tar.gz
rails-f7056c5ce8ff94c15f06556e42e0591efc3d2d98.tar.bz2
rails-f7056c5ce8ff94c15f06556e42e0591efc3d2d98.zip
Merge branch 'master' of git@github.com:lifo/docrails
-rw-r--r--activerecord/lib/active_record/aggregations.rb4
-rwxr-xr-xactiverecord/lib/active_record/base.rb52
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb53
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb49
-rw-r--r--activerecord/lib/active_record/transactions.rb87
-rw-r--r--railties/Rakefile5
-rw-r--r--railties/doc/guides/activerecord/association_basics.txt3
-rw-r--r--railties/doc/guides/activerecord/finders.txt54
-rw-r--r--railties/doc/guides/authors.txt8
-rw-r--r--railties/doc/guides/caching/caching_with_rails.txt350
-rw-r--r--railties/doc/guides/debugging/debugging_rails_applications.txt43
-rw-r--r--railties/doc/guides/index.txt9
-rw-r--r--railties/doc/guides/routing/routing_outside_in.txt2
13 files changed, 656 insertions, 63 deletions
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb
index 9eee7f2d98..1eefebb3b3 100644
--- a/activerecord/lib/active_record/aggregations.rb
+++ b/activerecord/lib/active_record/aggregations.rb
@@ -75,7 +75,7 @@ module ActiveRecord
#
# customer.balance = Money.new(20) # sets the Money value object and the attribute
# customer.balance # => Money value object
- # customer.balance.exchanged_to("DKK") # => Money.new(120, "DKK")
+ # customer.balance.exchange_to("DKK") # => Money.new(120, "DKK")
# customer.balance > Money.new(10) # => true
# customer.balance == Money.new(20) # => true
# customer.balance < Money.new(5) # => false
@@ -99,7 +99,7 @@ module ActiveRecord
# relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects.
#
# It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after
- # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that
+ # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchange_to method that
# returns a new value object instead of changing its own values. Active Record won't persist value objects that have been
# changed through means other than the writer method.
#
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 91b69747e0..556f9f115b 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -415,6 +415,31 @@ module ActiveRecord #:nodoc:
@@subclasses = {}
+ # Contains the database configuration - as is typically stored in config/database.yml -
+ # as a Hash.
+ #
+ # For example, the following database.yml...
+ #
+ # development:
+ # adapter: sqlite3
+ # database: db/development.sqlite3
+ #
+ # production:
+ # adapter: sqlite3
+ # database: db/production.sqlite3
+ #
+ # ...would result in ActiveRecord::Base.configurations to look like this:
+ #
+ # {
+ # 'development' => {
+ # 'adapter' => 'sqlite3',
+ # 'database' => 'db/development.sqlite3'
+ # },
+ # 'production' => {
+ # 'adapter' => 'sqlite3',
+ # 'database' => 'db/production.sqlite3'
+ # }
+ # }
cattr_accessor :configurations, :instance_writer => false
@@configurations = {}
@@ -1221,7 +1246,32 @@ module ActiveRecord #:nodoc:
end
end
- # Resets all the cached information about columns, which will cause them to be reloaded on the next request.
+ # Resets all the cached information about columns, which will cause them
+ # to be reloaded on the next request.
+ #
+ # The most common usage pattern for this method is probably in a migration,
+ # when just after creating a table you want to populate it with some default
+ # values, eg:
+ #
+ # class CreateJobLevels < ActiveRecord::Migration
+ # def self.up
+ # create_table :job_levels do |t|
+ # t.integer :id
+ # t.string :name
+ #
+ # t.timestamps
+ # end
+ #
+ # JobLevel.reset_column_information
+ # %w{assistant executive manager director}.each do |type|
+ # JobLevel.create(:name => type)
+ # end
+ # end
+ #
+ # def self.down
+ # drop_table :job_levels
+ # end
+ # end
def reset_column_information
generated_methods.each { |name| undef_method(name) }
@column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = @generated_methods = @inheritance_column = nil
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 54a39db1eb..e3e0839f96 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -11,6 +11,21 @@ module ActiveRecord
# Connection pool base class for managing ActiveRecord database
# connections.
#
+ # == Introduction
+ #
+ # A connection pool synchronizes thread access to a limited number of
+ # database connections. The basic idea is that each thread checks out a
+ # database connection from the pool, uses that connection, and checks the
+ # connection back in. ConnectionPool is completely thread-safe, and will
+ # ensure that a connection cannot be used by two threads at the same time,
+ # as long as ConnectionPool's contract is correctly followed. It will also
+ # handle cases in which there are more threads than connections: if all
+ # connections have been checked out, and a thread tries to checkout a
+ # connection anyway, then ConnectionPool will wait until some other thread
+ # has checked in a connection.
+ #
+ # == Obtaining (checking out) a connection
+ #
# Connections can be obtained and used from a connection pool in several
# ways:
#
@@ -28,6 +43,11 @@ module ActiveRecord
# obtains a connection, yields it as the sole argument to the block,
# and returns it to the pool after the block completes.
#
+ # Connections in the pool are actually AbstractAdapter objects (or objects
+ # compatible with AbstractAdapter's interface).
+ #
+ # == Options
+ #
# There are two connection-pooling-related options that you can add to
# your database connection configuration:
#
@@ -37,6 +57,12 @@ module ActiveRecord
class ConnectionPool
attr_reader :spec
+ # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
+ # object which describes database connection information (e.g. adapter,
+ # host name, username, password, etc), as well as the maximum size for
+ # this ConnectionPool.
+ #
+ # The default ConnectionPool maximum size is 5.
def initialize(spec)
@spec = spec
# The cache of reserved connections mapped to threads
@@ -87,7 +113,7 @@ module ActiveRecord
!@connections.empty?
end
- # Disconnect all connections in the pool.
+ # Disconnects all connections in the pool, and clears the pool.
def disconnect!
@reserved_connections.each do |name,conn|
checkin conn
@@ -128,7 +154,22 @@ module ActiveRecord
end
end
- # Check-out a database connection from the pool.
+ # Check-out a database connection from the pool, indicating that you want
+ # to use it. You should call #checkin when you no longer need this.
+ #
+ # This is done by either returning an existing connection, or by creating
+ # a new connection. If the maximum number of connections for this pool has
+ # already been reached, but the pool is empty (i.e. they're all being used),
+ # then this method will wait until a thread has checked in a connection.
+ # The wait time is bounded however: if no connection can be checked out
+ # within the timeout specified for this pool, then a ConnectionTimeoutError
+ # exception will be raised.
+ #
+ # Returns: an AbstractAdapter object.
+ #
+ # Raises:
+ # - ConnectionTimeoutError: no connection can be obtained from the pool
+ # within the timeout period.
def checkout
# Checkout an available connection
conn = @connection_mutex.synchronize do
@@ -150,7 +191,11 @@ module ActiveRecord
end
end
- # Check-in a database connection back into the pool.
+ # Check-in a database connection back into the pool, indicating that you
+ # no longer need this connection.
+ #
+ # +conn+: an AbstractAdapter object, which was obtained by earlier by
+ # calling +checkout+ on this pool.
def checkin(conn)
@connection_mutex.synchronize do
conn.run_callbacks :checkin
@@ -275,4 +320,4 @@ module ActiveRecord
end
end
end
-end \ No newline at end of file
+end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 7c37916367..c5183357a1 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -13,15 +13,19 @@ require 'active_record/connection_adapters/abstract/query_cache'
module ActiveRecord
module ConnectionAdapters # :nodoc:
+ # ActiveRecord supports multiple database systems. AbstractAdapter and
+ # related classes form the abstraction layer which makes this possible.
+ # An AbstractAdapter represents a connection to a database, and provides an
+ # abstract interface for database-specific functionality such as establishing
+ # a connection, escaping values, building the right SQL fragments for ':offset'
+ # and ':limit' options, etc.
+ #
# All the concrete database adapters follow the interface laid down in this class.
- # You can use this interface directly by borrowing the database connection from the Base with
- # Base.connection.
+ # ActiveRecord::Base.connection returns an AbstractAdapter object, which
+ # you can use.
#
- # Most of the methods in the adapter are useful during migrations. Most
- # notably, SchemaStatements#create_table, SchemaStatements#drop_table,
- # SchemaStatements#add_index, SchemaStatements#remove_index,
- # SchemaStatements#add_column, SchemaStatements#change_column and
- # SchemaStatements#remove_column are very useful.
+ # Most of the methods in the adapter are useful during migrations. Most
+ # notably, the instance methods provided by SchemaStatement are very useful.
class AbstractAdapter
include Quoting, DatabaseStatements, SchemaStatements
include QueryCache
@@ -91,26 +95,31 @@ module ActiveRecord
# CONNECTION MANAGEMENT ====================================
- # Is this connection active and ready to perform queries?
+ # Checks whether the connection to the database is still active. This includes
+ # checking whether the database is actually capable of responding, i.e. whether
+ # the connection isn't stale.
def active?
@active != false
end
- # Close this connection and open a new one in its place.
+ # Disconnects from the database if already connected, and establishes a
+ # new connection with the database.
def reconnect!
@active = true
end
- # Close this connection
+ # Disconnects from the database if already connected. Otherwise, this
+ # method does nothing.
def disconnect!
@active = false
end
# Reset the state of this connection, directing the DBMS to clear
# transactions and other connection-related server-side state. Usually a
- # database-dependent operation; the default method simply executes a
- # ROLLBACK and swallows any exceptions which is probably not enough to
- # ensure the connection is clean.
+ # database-dependent operation.
+ #
+ # The default implementation does nothing; the implementation should be
+ # overridden by concrete adapters.
def reset!
# this should be overridden by concrete adapters
end
@@ -121,15 +130,19 @@ module ActiveRecord
false
end
- # Verify this connection by calling <tt>active?</tt> and reconnecting if
- # the connection is no longer active.
+ # Checks whether the connection to the database is still active (i.e. not stale).
+ # This is done under the hood by calling <tt>active?</tt>. If the connection
+ # is no longer active, then this method will reconnect to the database.
def verify!(*ignored)
reconnect! unless active?
end
- # Provides access to the underlying database connection. Useful for
- # when you need to call a proprietary method such as postgresql's lo_*
- # methods
+ # Provides access to the underlying database driver for this adapter. For
+ # example, this method returns a Mysql object in case of MysqlAdapter,
+ # and a PGconn object in case of PostgreSQLAdapter.
+ #
+ # This is useful for when you need to call a proprietary method such as
+ # PostgreSQL's lo_* methods.
def raw_connection
@connection
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 970da701c7..27b5aca18f 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -1,7 +1,8 @@
require 'thread'
module ActiveRecord
- module Transactions # :nodoc:
+ # See ActiveRecord::Transactions::ClassMethods for documentation.
+ module Transactions
class TransactionError < ActiveRecordError # :nodoc:
end
@@ -15,26 +16,33 @@ module ActiveRecord
end
end
- # Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action.
- # The classic example is a transfer between two accounts where you can only have a deposit if the withdrawal succeeded and
- # vice versa. Transactions enforce the integrity of the database and guard the data against program errors or database break-downs.
- # So basically you should use transaction blocks whenever you have a number of statements that must be executed together or
- # not at all. Example:
+ # Transactions are protective blocks where SQL statements are only permanent
+ # if they can all succeed as one atomic action. The classic example is a
+ # transfer between two accounts where you can only have a deposit if the
+ # withdrawal succeeded and vice versa. Transactions enforce the integrity of
+ # the database and guard the data against program errors or database
+ # break-downs. So basically you should use transaction blocks whenever you
+ # have a number of statements that must be executed together or not at all.
+ # Example:
#
- # transaction do
+ # ActiveRecord::Base.transaction do
# david.withdrawal(100)
# mary.deposit(100)
# end
#
- # This example will only take money from David and give to Mary if neither +withdrawal+ nor +deposit+ raises an exception.
- # Exceptions will force a ROLLBACK that returns the database to the state before the transaction was begun. Be aware, though,
- # that the objects will _not_ have their instance data returned to their pre-transactional state.
+ # This example will only take money from David and give to Mary if neither
+ # +withdrawal+ nor +deposit+ raises an exception. Exceptions will force a
+ # ROLLBACK that returns the database to the state before the transaction was
+ # begun. Be aware, though, that the objects will _not_ have their instance
+ # data returned to their pre-transactional state.
#
# == Different Active Record classes in a single transaction
#
# Though the transaction class method is called on some Active Record class,
# the objects within the transaction block need not all be instances of
- # that class.
+ # that class. This is because transactions are per-database connection, not
+ # per-model.
+ #
# In this example a <tt>Balance</tt> record is transactionally saved even
# though <tt>transaction</tt> is called on the <tt>Account</tt> class:
#
@@ -43,6 +51,14 @@ module ActiveRecord
# account.save!
# end
#
+ # Note that the +transaction+ method is also available as a model instance
+ # method. For example, you can also do this:
+ #
+ # balance.transaction do
+ # balance.save!
+ # account.save!
+ # end
+ #
# == Transactions are not distributed across database connections
#
# A transaction acts on a single database connection. If you have
@@ -62,17 +78,48 @@ module ActiveRecord
#
# == Save and destroy are automatically wrapped in a transaction
#
- # Both Base#save and Base#destroy come wrapped in a transaction that ensures that whatever you do in validations or callbacks
- # will happen under the protected cover of a transaction. So you can use validations to check for values that the transaction
- # depends on or you can raise exceptions in the callbacks to rollback, including <tt>after_*</tt> callbacks.
+ # Both Base#save and Base#destroy come wrapped in a transaction that ensures
+ # that whatever you do in validations or callbacks will happen under the
+ # protected cover of a transaction. So you can use validations to check for
+ # values that the transaction depends on or you can raise exceptions in the
+ # callbacks to rollback, including <tt>after_*</tt> callbacks.
#
# == Exception handling and rolling back
#
- # Also have in mind that exceptions thrown within a transaction block will be propagated (after triggering the ROLLBACK), so you
- # should be ready to catch those in your application code.
+ # Also have in mind that exceptions thrown within a transaction block will
+ # be propagated (after triggering the ROLLBACK), so you should be ready to
+ # catch those in your application code.
#
- # One exception is the ActiveRecord::Rollback exception, which will trigger a ROLLBACK when raised,
- # but not be re-raised by the transaction block.
+ # One exception is the ActiveRecord::Rollback exception, which will trigger
+ # a ROLLBACK when raised, but not be re-raised by the transaction block.
+ #
+ # *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
+ # inside a transaction block. StatementInvalid exceptions indicate that an
+ # error occurred at the database level, for example when a unique constraint
+ # is violated. On some database systems, such as PostgreSQL, database errors
+ # inside a transaction causes the entire transaction to become unusable
+ # until it's restarted from the beginning. Here is an example which
+ # demonstrates the problem:
+ #
+ # # Suppose that we have a Number model with a unique column called 'i'.
+ # Number.transaction do
+ # Number.create(:i => 0)
+ # begin
+ # # This will raise a unique constraint error...
+ # Number.create(:i => 0)
+ # rescue ActiveRecord::StatementInvalid
+ # # ...which we ignore.
+ # end
+ #
+ # # On PostgreSQL, the transaction is now unusable. The following
+ # # statement will cause a PostgreSQL error, even though the unique
+ # # constraint is no longer violated:
+ # Number.create(:i => 1)
+ # # => "PGError: ERROR: current transaction is aborted, commands
+ # # ignored until end of transaction block"
+ # end
+ #
+ # One should restart the entire transaction if a StatementError occurred.
module ClassMethods
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
def transaction(&block)
@@ -86,6 +133,7 @@ module ActiveRecord
end
end
+ # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
def transaction(&block)
self.class.transaction(&block)
end
@@ -122,6 +170,9 @@ module ActiveRecord
# Executes +method+ within a transaction and captures its return value as a
# status flag. If the status is true the transaction is committed, otherwise
# a ROLLBACK is issued. In any case the status flag is returned.
+ #
+ # This method is available within the context of an ActiveRecord::Base
+ # instance.
def with_transaction_returning_status(method, *args)
status = nil
transaction do
diff --git a/railties/Rakefile b/railties/Rakefile
index 39c0ec89e7..be37023a1d 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -277,14 +277,15 @@ Rake::RDocTask.new { |rdoc|
# doesn't equal its folder name, then specify a hash: { 'folder_name' => 'basename' }
guides = [
'getting_started_with_rails',
- 'securing_rails_applications',
'testing_rails_applications',
'creating_plugins',
'migrations',
+ { 'securing_rails_applications' => 'security' },
{ 'routing' => 'routing_outside_in' },
{ 'forms' =>'form_helpers' },
{ 'activerecord' => 'association_basics' },
- { 'debugging' => 'debugging_rails_applications' }
+ { 'debugging' => 'debugging_rails_applications' },
+ { 'caching' => 'caching_with_rails' }
]
guides_html_files = [] # autogenerated from the 'guides' variable.
diff --git a/railties/doc/guides/activerecord/association_basics.txt b/railties/doc/guides/activerecord/association_basics.txt
index 704971d0e8..58c4738a49 100644
--- a/railties/doc/guides/activerecord/association_basics.txt
+++ b/railties/doc/guides/activerecord/association_basics.txt
@@ -104,10 +104,11 @@ end
=== The +has_many+ Association
A +has_many+ association indicates a one-to-many connection with another model. You'll often find this association on the "other side" of a +belongs_to+ association. This association indicates that each instance of the model has zero or more instances of another model. For example, in an application containing customers and orders, the customer model could be declared like this:
+
[source, ruby]
-------------------------------------------------------
class Customer < ActiveRecord::Base
- has_many :customers
+ has_many :orders
end
-------------------------------------------------------
diff --git a/railties/doc/guides/activerecord/finders.txt b/railties/doc/guides/activerecord/finders.txt
new file mode 100644
index 0000000000..9f3abb210a
--- /dev/null
+++ b/railties/doc/guides/activerecord/finders.txt
@@ -0,0 +1,54 @@
+Rails Finders
+=======================
+First Draft
+Ryan Bigg <radarlistener@gmail.com>
+
+== What is this guide about? ==
+This guide is all about the `find` method defined in ActiveRecord::Base, and associated goodness such as named scopes.
+
+== In the beginning... ==
+
+In the beginning there was SQL. SQL looked like this:
+
+[source,SQL]
+SELECT * FROM forums
+SELECT * FROM forums WHERE id = '1'
+SELECT * FROM forums LIMIT 0,1
+SELECT * FROM forums ORDER BY id DESC LIMIT 0,1
+
+In Rails you don't have to type SQL, unlike other languages, because ActiveRecord is there to help you find your records. When you define a model like so,
+
+[source,Ruby on Rails]
+class Forum < ActiveRecord::Base
+
+end
+[/code]
+
+== First, Last and All ==
+
+you're telling Ruby to create a new class called `Forum` and that should inherit from ActiveRecord::Base. ActiveRecord::Base has methods defined on it to make interacting with your database and the tables within it much, much easier. For example if you wanted to find the first forum you would simply type `Forum.find(:first)` and that would find the first forum created in your database, the SQL equivalent of typing `SELECT * FROM forums LIMIT 0,1`. Alternatively, you could use the pre-defined named scope first, calling `Forum.first` instead. `first` has two similiar methods, `all` and `last`, which will find all objects in that model's table, and the last object in that model's table respectively. These can be used exactly like first, `Forum.all` is an alias to `Forum.find(:all)` and `Forum.last` is an alias to `Forum.find(:last)`.
+
+`Forum.first` and `Forum.last` will both return a single object, where as `Forum.find(:all)` will return an array of Forum objects.
+
+== Conditions ==
+
+If you'd like to add conditions to your find, you could just specify them in there, just like `Forum.find(:first, :conditions => "viewable_by = '2'")`. Now what if that number could vary, say as a parameter from somewhere, or perhaps from the user's level status somewhere? The find then becomes something like `Forum.find(:first, :conditions => ["viewable_by = ?", params[:level]])`. ActiveRecord will go through the first element in the conditions option and any additional elements will replace the question marks (?) in the first element. If you want to specify two conditions, you can do it like `Forum.find(:first, :conditions => ["viewable_by = ? AND locked = ?", params[:level], params[:locked]])`.
+
+
+== Ordering ==
+
+If you're getting a set of records and want to force an order, you can use `Forum.find(:all, :order => "created_at")` which by default will sort the records by ascending order. If you'd like to order it in descending order, just tell it to do that using `Forum.find(:all, :order => "created_at desc")
+
+== Selecting Certain Fields ==
+
+To select certain fields, you can use the select option like this: `Forum.find(:first, :select => "viewable_by, locked")`. This select option does not use an array of fields, but rather requires you to type SQL-like code. The above code will execute `SELECT viewable_by, locked FROM forums LIMIT 0,1` on your database.
+
+== Includes vs Joins ==
+
+== Named Scopes ==
+
+== Finding on Associations ==
+
+== Making It All Work Together ==
+
+You can chain these options together in no particular order as ActiveRecord will write the correct SQL for you. For example you could do this: `Forum.find(:all, :order => "created_at DESC", :select => "viewable_by, created_at", :conditions => ["viewable_by = ?", params[:level]], :limit => 10), which should execute a query like `SELECT viewable_by, created_at FROM forums WHERE ORDER BY created_at DESC LIMIT 0,10` if you really wanted it.
diff --git a/railties/doc/guides/authors.txt b/railties/doc/guides/authors.txt
index 39307a08e9..132121ed3c 100644
--- a/railties/doc/guides/authors.txt
+++ b/railties/doc/guides/authors.txt
@@ -13,4 +13,12 @@ He is based in Cambridge (UK) and when not consuming fine ales he blogs at http:
***********************************************************
Mike Gunderloy is an independent consultant who brings 25 years of experience in a variety of languages to bear on his current
work with Rails. His near-daily links and other blogging can be found at http://afreshcup.com[A Fresh Cup].
+***********************************************************
+
+.Emilio Tagua
+[[miloops]]
+***********************************************************
+Emilio Tagua -- a.k.a. miloops -- is an Argentinian entrepreneur, developer, open source contributor and Rails evangelist.
+Cofounder of http://www.eventioz.com[Eventioz]. He has been using Rails since 2006 and contributing since early 2008.
+Can be found at gmail, twitter, freenode, everywhere as miloops.
*********************************************************** \ No newline at end of file
diff --git a/railties/doc/guides/caching/caching_with_rails.txt b/railties/doc/guides/caching/caching_with_rails.txt
new file mode 100644
index 0000000000..54b7445f88
--- /dev/null
+++ b/railties/doc/guides/caching/caching_with_rails.txt
@@ -0,0 +1,350 @@
+Caching with Rails: An overview
+===============================
+
+Everyone caches. This guide will teach you what you need to know about
+avoiding that expensive round-trip to your database and returning what you
+need to return to those hungry web clients in the shortest time possible.
+
+Specifically, this guide is split into two parts:
+
+- Basic Caching
+- Advanced Caching
+
+- Basic Caching
+ * Page Caching
+ * Action Caching
+ * Fragment Caching
+ * Cache Sweeping
+ * SQL Caching
+ * Cache stores
+
+- Advanced Caching
+ * Fragment Caching with interlock and memcached
+ * Model Caching with cache_fu and memcached
+ * Things you wish you didn't know
+
+== Basic Caching
+
+This is an introduction to the three types of caching techniques that Rails
+provides by default without the use of any third party plugins.
+
+To get started make sure Base.perform_caching is set to true for your
+environment.
+
+[source, ruby]
+-----------------------------------------------------
+Base.perform_caching = true
+-----------------------------------------------------
+
+=== Page Caching
+
+Page caching is a Rails mechanism which allows the request for a generated
+page to be fulfilled by the webserver, without ever having to go through the
+Rails stack at all. Obviously, this is super fast. Unfortunately, it can't be
+applied to every situation (such as pages that need authentication) and since
+the webserver is literally just serving a file from the filesystem, cache
+expiration is an issue that needs to be dealt with.
+
+So, how do you enable this super-fast cache behavior? Simple, let's say you
+have a controller called ProductController and a 'list' action that lists all
+the products
+
+[source, ruby]
+-----------------------------------------------------
+class ProductController < ActionController
+
+ caches_page :list
+
+ def list; end
+
+end
+-----------------------------------------------------
+
+The first time anyone requestsion products/list, Rails will generate a file
+called list.html and the webserver will then look for that file before it
+passes the next request for products/list to your Rails application.
+
+By default, the page cache directory is set to Rails.public_path (which is
+usually set to RAILS_ROOT + "/public") and this can be configured by changing
+the configuration setting Base.cache_public_directory
+
+The page caching mechanism will automatically add a .html exxtension to
+requests for pages that do not have an extension to make it easy for the
+webserver to find those pages and this can be configured by changing the
+configuration setting Base.page_cache_extension
+
+In order to expire this page when a new product is added we could extend our
+example controler like this:
+
+[source, ruby]
+-----------------------------------------------------
+class ProductController < ActionController
+
+ caches_page :list
+
+ def list; end
+
+ def create
+ expires_page :action => :list
+ end
+
+end
+-----------------------------------------------------
+
+If you want a more complicated expiration scheme, you can use cache sweepers
+to expire cached objects when things change. This is covered in the section on Sweepers.
+
+[More: caching paginated results? more examples? Walk-through of page caching?]
+
+=== Action Caching
+
+The issue with page caching is that you cannot use it for pages that require
+to restrict access somehow. This is where Action Caching comes in. Action
+Caching works like Page Caching except for the fact that the incoming web
+request does go from the webserver to the Rails stack and Action Pack so that
+before_filters can be run on it before the cache is served, so that
+authentication and other restrictions can be used while still serving the
+result of the output from a cached copy.
+
+Clearing the cache works in the exact same way as with Page Caching.
+
+Let's say you only wanted authenticated users to edit or create a Product
+object, but still cache those pages:
+
+[source, ruby]
+-----------------------------------------------------
+class ProductController < ActionController
+
+ before_filter :authenticate, :only => [ :edit, :create ]
+ caches_page :list
+ caches_action :edit
+
+ def list; end
+
+ def create
+ expires_page :action => :list
+ expire_action :action => :edit
+ end
+
+ def edit; end
+
+end
+-----------------------------------------------------
+
+[More: more examples? Walk-through of action caching from request to response?
+ Description of Rake tasks to clear cached files? Show example of
+ subdomain caching? Talk about :cache_path, :if and assing blocks/Procs
+ to expire_action?]
+
+=== Fragment Caching
+
+Life would be perfect if we could get away with caching the entire contents of
+a page or action and serving it out to the world. Unfortunately, dynamic web
+applications usually build pages with a variety of components not all of which
+have the same caching characteristics. In order to address such a dynamically
+created page where different parts of the page need to be cached and expired
+differently Rails provides a mechanism called Fragment caching.
+
+Fragment caching allows a fragment of view logic to be wrapped in a cache
+block and served out of the cache store when the next request comes in.
+
+As an example, if you wanted to show all the orders placed on your website in
+real time and didn't want to cache that part of the page, but did want to
+cache the part of the page which lists all products available, you could use
+this piece of code:
+
+[source, ruby]
+-----------------------------------------------------
+<% Order.find_recent.each do |o| %>
+ <%= o.buyer.name %> bought <% o.product.name %>
+<% end %>
+
+<% cache do %>
+ All available products:
+ <% Product.find(:all).each do |p| %>
+ <%= link_to p.name, product_url(p) %>
+ <% end %>
+<% end %>
+-----------------------------------------------------
+
+The cache block in our example will bind to the action that called it and is
+written out to the same place as the Action Cache, which means that if you
+want to cache multiple fragments per action, you should provide an action_path to the cache call:
+
+[source, ruby]
+-----------------------------------------------------
+<% cache(:action => 'recent', :action_suffix => 'all_products') do %>
+ All available products:
+-----------------------------------------------------
+
+and you can expire it using the expire_fragment method, like so:
+
+[source, ruby]
+-----------------------------------------------------
+expire_fragment(:controller => 'producst', :action => 'recent', :action_suffix => 'all_products)
+-----------------------------------------------------
+
+[More: more examples? description of fragment keys and expiration, etc? pagination?]
+
+=== Sweepers
+
+Cache sweeping is a mechanism which allows you to get around having a ton of
+expire_{page,action,fragment) calls in your code by moving all the work
+required to expire cached content into an asynchronous process that watches
+for changes to your models and implements callbacks to expire cached content.
+
+Continuing with our Product controller example, we could rewrite it with a
+sweeper such as the following:
+
+[source, ruby]
+-----------------------------------------------------
+class StoreSweeper < ActionController::Caching::Sweeper
+ observe Product # This sweeper is going to keep an eye on the Post model
+
+ # If our sweeper detects that a Post was created call this
+ def after_create(product)
+ expire_cache_for(product)
+ end
+
+ # If our sweeper detects that a Post was updated call this
+ def after_update(product)
+ expire_cache_for(product)
+ end
+
+ # If our sweeper detects that a Post was deleted call this
+ def after_destroy(product)
+ expire_cache_for(product)
+ end
+
+ private
+ def expire_cache_for(record)
+ # Expire the list page now that we added a new product
+ expire_page(:controller => '#{record}', :action => 'list')
+
+ # Expire a fragment
+ expire_fragment(:controller => '#{record}', :action => 'recent', :action_suffix => 'all_products')
+ end
+end
+-----------------------------------------------------
+
+Then we add it to our controller to tell it to call the sweeper when certain
+actions are called. So, if we wanted to expire the cached content for the list
+and edit actions when the create action was called, we could do the following:
+
+[source, ruby]
+-----------------------------------------------------
+class ProductController < ActionController
+
+ before_filter :authenticate, :only => [ :edit, :create ]
+ caches_page :list
+ caches_action :edit
+ cache_sweeper :store_sweeper, :only => [ :create ]
+
+ def list; end
+
+ def create
+ expires_page :action => :list
+ expire_action :action => :edit
+ end
+
+ def edit; end
+
+end
+-----------------------------------------------------
+
+[More: more examples? better sweepers?]
+
+=== SQL Caching
+
+Query caching is a Rails feature that caches the result set returned by each
+query so that if Rails encounters the same query again for that request, it
+will used the cached result set as opposed to running the query against the
+database again.
+
+For example:
+
+[source, ruby]
+-----------------------------------------------------
+class ProductController < ActionController
+
+ before_filter :authenticate, :only => [ :edit, :create ]
+ caches_page :list
+ caches_action :edit
+ cache_sweeper :store_sweeper, :only => [ :create ]
+
+ def list
+ # Run a find query
+ Product.find(:all)
+
+ ...
+
+ # Run the same query again
+ Product.find(:all)
+ end
+
+ def create
+ expires_page :action => :list
+ expire_action :action => :edit
+ end
+
+ def edit; end
+
+end
+-----------------------------------------------------
+
+In the 'list' action above, the result set returned by the first
+Product.find(:all) will be cached and will be used to avoid querying the
+database again the second time that finder is called.
+
+Query caches are created at the start of an action and destroyed at the end of
+that action and thus persist only for the duration of the action.
+
+=== Cache stores
+
+Rails provides different stores for the cached data for action and fragment
+caches. Page caches are always stored on disk.
+
+The cache stores provided include:
+
+1) Memory store: Cached data is stored in the memory allocated to the Rails
+ process
+[source, ruby]
+-----------------------------------------------------
+ActionController::Base.cache_store = :memory_store
+-----------------------------------------------------
+
+2) File store: Cached data is stored on the disk, this is the default store
+ and the default path for this store is: /tmp/cache
+
+[source, ruby]
+-----------------------------------------------------
+ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"
+-----------------------------------------------------
+
+3) DRb store: Cached data is stored in a separate DRb process that all servers
+communicate with
+
+[source, ruby]
+-----------------------------------------------------
+ActionController::Base.cache_store = :drb_store, "druby://localhost:9192"
+-----------------------------------------------------
+
+4) MemCached store: Cached data is stored using a high-speed caching server
+called memcached
+
+[source, ruby]
+-----------------------------------------------------
+ActionController::Base.cache_store = :mem_cache_store, "localhost"
+-----------------------------------------------------
+
+5) Custom store: You can define your own cache store (new in Rails 2.1)
+
+[source, ruby]
+-----------------------------------------------------
+ActionController::Base.cache_store = MyOwnStore.new("parameter")
+-----------------------------------------------------
+
+== Advanced Caching
+
+=== memcached and cache_fu
+=== memcached and interlock
diff --git a/railties/doc/guides/debugging/debugging_rails_applications.txt b/railties/doc/guides/debugging/debugging_rails_applications.txt
index eb1135d094..37d4dd19d6 100644
--- a/railties/doc/guides/debugging/debugging_rails_applications.txt
+++ b/railties/doc/guides/debugging/debugging_rails_applications.txt
@@ -1,4 +1,4 @@
-Debugging Rails applications
+Debugging Rails Applications
============================
This guide covers how to debug Ruby on Rails applications. By referring to this guide, you will be able to:
@@ -8,7 +8,13 @@ This guide covers how to debug Ruby on Rails applications. By referring to this
* Learn the different ways of debugging
* Analyze the stack trace
-== View helpers for debugging
+== View Helpers for Debugging
+
+One common task is to inspect the contents of a variable. In Rails, you can do this with three methods:
+
+* `debug`
+* `to_yaml`
+* `inspect`
=== debug
@@ -40,8 +46,7 @@ attributes_cache: {}
Title: Rails debugging guide
----------------------------------------------------------------------------
-
-=== do it yourself
+=== to_yaml
Displaying an instance variable, or any other object or method, in yaml format can be achieved this way:
@@ -72,6 +77,8 @@ attributes_cache: {}
Title: Rails debugging guide
----------------------------------------------------------------------------
+=== inspect
+
Another useful method for displaying object values is `inspect`, especially when working with arrays or hashes, it will print the object value as a string, for example:
[source, html]
@@ -91,13 +98,13 @@ Will be rendered as follows:
Title: Rails debugging guide
----------------------------------------------------------------------------
-== The logger
+== The Logger
=== What is it?
-Rails makes use of ruby’s standard `logger`, `Log4r`, or another logger that provides a similar interface can also be substituted if you wish.
+Rails makes use of ruby's standard `logger` to write log information. You can also substitute another logger such as `Log4R` if you wish.
-If you want to change the logger you can specify it in your `environment.rb` or any environment file.
+If you want to change the logger you can specify it in your +environment.rb+ or any environment file.
[source, ruby]
----------------------------------------------------------------------------
@@ -114,9 +121,9 @@ config.logger = Log4r::Logger.new("Application Log")
----------------------------------------------------------------------------
[TIP]
-By default, each log is created under `RAILS_ROOT/log/` and the log file name is `environment_name.log`.
+By default, each log is created under `RAILS_ROOT/log/` and the log file name is +environment_name.log+.
-=== Log levels
+=== Log Levels
When something is logged it's printed into the corresponding log if the message log level is equal or higher than the configured log level. If you want to know the current log level just call `ActiveRecord::Base.logger.level` method.
@@ -133,7 +140,7 @@ This is useful when you want to log under development or staging, but you don't
[TIP]
Rails default log level is +info+ in production mode and +debug+ in development and test mode.
-=== Sending messages
+=== Sending Messages
To write in the current log use the `logger.(debug|info|warn|error|fatal)` method from within a controller, model or mailer:
@@ -236,7 +243,7 @@ In development mode, you can dynamically `require \'ruby-debug\'` instead of res
In order to use Rails debugging you'll need to be running either *WEBrick* or *Mongrel*. For the moment, no alternative servers are supported.
-=== The shell
+=== The Shell
As soon as your application calls the `debugger` method, the debugger will be started in a debugger shell inside the terminal window you've fired up your application server and you will be placed in the ruby-debug's prompt `(rdb:n)`. The _n_ is the thread number.
@@ -305,7 +312,7 @@ If we do it again, this time using just `l`, the next ten lines of the file will
And so on until the end of the current file, when the end of file is reached, it will start again from the beginning of the file and continue again up to the end, acting as a circular buffer.
-=== The context
+=== The Context
When we start debugging your application, we will be placed in different contexts as you go through the different parts of the stack.
A context will be created when a stopping point or an event is reached. It has information about the suspended program which enable a debugger to inspect the frame stack, evaluate variables from the perspective of the debugged program, and contains information about the place the debugged program is stopped.
@@ -349,7 +356,7 @@ The debugger can list, stop, resume and switch between running threads, the comm
This command is very helpful, among other occasions, when you are debugging concurrent threads and need to verify that there are no race conditions in your code.
-=== Inspecting variables
+=== Inspecting Variables
Any expression can be evaluated in the current context, just type it!
@@ -422,7 +429,7 @@ We can use also `display` to start watching variables, this is a good way of tra
The variables inside the displaying list will be printed with their values after we move in the stack. To stop displaying a variable use `undisplay _n_` where _n_ is the variable number (1 in the last example).
-=== Step by step
+=== Step by Step
Now you should know where you are in the running trace and be able to print the available variables. But lets continue and move on with the application execution.
@@ -601,4 +608,10 @@ set listsize 25
* link:http://railscasts.com/episodes/56-the-logger[Ryan Bate's logger screencast]
* link:http://bashdb.sourceforge.net/ruby-debug.html[Debugging with ruby-debug]
* link:http://cheat.errtheblog.com/s/rdebug/[ruby-debug cheat sheet]
-* link:http://wiki.rubyonrails.org/rails/pages/HowtoConfigureLogging[Ruby on Rails Wiki: How to Configure Logging] \ No newline at end of file
+* link:http://wiki.rubyonrails.org/rails/pages/HowtoConfigureLogging[Ruby on Rails Wiki: How to Configure Logging]
+
+== Changelog ==
+
+http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/5[Lighthouse ticket]
+
+* September 16, 2008: initial version by link:../authors.html#miloops[Emilio Tagua] \ No newline at end of file
diff --git a/railties/doc/guides/index.txt b/railties/doc/guides/index.txt
index 87d6804ead..45002f874a 100644
--- a/railties/doc/guides/index.txt
+++ b/railties/doc/guides/index.txt
@@ -1,6 +1,8 @@
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]
***********************************************************
TODO: Insert some description here.
@@ -28,7 +30,7 @@ in Rails. It covers everything from ``What is a test?'' to the testing APIs.
Enjoy.
***********************************************************
-.link:securing_rails_applications/securing_rails_applications.html[Securing Rails Applications]
+.link:securing_rails_applications/security.html[Securing Rails Applications]
***********************************************************
This manual describes common security problems in web applications and how to
avoid them with Rails.
@@ -51,3 +53,8 @@ of your code.
***********************************************************
TODO: Insert some description here.
***********************************************************
+
+.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 415ab92f34..2e48ca59b7 100644
--- a/railties/doc/guides/routing/routing_outside_in.txt
+++ b/railties/doc/guides/routing/routing_outside_in.txt
@@ -750,7 +750,7 @@ map.index :controller => "pages", :action => "main"
map.root :index
-------------------------------------------------------
-Because of the top-down processing of the file, the named route must be specified _before_ the call to +map.route+.
+Because of the top-down processing of the file, the named route must be specified _before_ the call to +map.root+.
=== Connecting the Empty String