aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
Diffstat (limited to 'railties')
-rw-r--r--railties/CHANGELOG9
-rw-r--r--railties/README.rdoc15
-rw-r--r--railties/guides/code/getting_started/Gemfile5
-rw-r--r--railties/guides/code/getting_started/config/environments/production.rb5
-rw-r--r--railties/guides/source/action_controller_overview.textile12
-rw-r--r--railties/guides/source/active_record_basics.textile57
-rw-r--r--railties/guides/source/active_record_querying.textile106
-rw-r--r--railties/guides/source/active_record_validations_callbacks.textile125
-rw-r--r--railties/guides/source/active_support_core_extensions.textile16
-rw-r--r--railties/guides/source/ajax_on_rails.textile72
-rw-r--r--railties/guides/source/asset_pipeline.textile54
-rw-r--r--railties/guides/source/association_basics.textile48
-rw-r--r--railties/guides/source/caching_with_rails.textile8
-rw-r--r--railties/guides/source/command_line.textile16
-rw-r--r--railties/guides/source/configuring.textile41
-rw-r--r--railties/guides/source/engines.textile606
-rw-r--r--railties/guides/source/getting_started.textile124
-rw-r--r--railties/guides/source/initialization.textile4
-rw-r--r--railties/guides/source/layouts_and_rendering.textile74
-rw-r--r--railties/guides/source/migrations.textile64
-rw-r--r--railties/guides/source/rails_on_rack.textile5
-rw-r--r--railties/guides/source/routing.textile2
-rw-r--r--railties/guides/source/security.textile10
-rw-r--r--railties/lib/rails/application.rb5
-rw-r--r--railties/lib/rails/application/bootstrap.rb4
-rw-r--r--railties/lib/rails/application/configuration.rb29
-rw-r--r--railties/lib/rails/commands/application.rb8
-rw-r--r--railties/lib/rails/commands/server.rb2
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/actions.rb4
-rw-r--r--railties/lib/rails/generators/app_base.rb25
-rw-r--r--railties/lib/rails/generators/base.rb6
-rw-r--r--railties/lib/rails/generators/rails/app/USAGE6
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb7
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/gitignore20
-rw-r--r--railties/lib/rails/generators/resource_helpers.rb2
-rw-r--r--railties/lib/rails/initializable.rb5
-rw-r--r--railties/lib/rails/rack.rb1
-rw-r--r--railties/lib/rails/rack/content_length.rb38
-rw-r--r--railties/lib/rails/rack/logger.rb38
-rw-r--r--railties/lib/rails/tasks/engine.rake1
-rw-r--r--railties/lib/rails/tasks/misc.rake2
-rw-r--r--railties/lib/rails/test_help.rb2
-rw-r--r--railties/lib/rails/test_unit/testing.rake2
-rw-r--r--railties/test/application/assets_test.rb89
-rw-r--r--railties/test/application/configuration_test.rb8
-rw-r--r--railties/test/application/middleware/cache_test.rb14
-rw-r--r--railties/test/application/middleware_test.rb1
-rw-r--r--railties/test/generators/actions_test.rb28
-rw-r--r--railties/test/generators/app_generator_test.rb25
-rw-r--r--railties/test/generators/assets_generator_test.rb2
-rw-r--r--railties/test/initializable_test.rb4
-rw-r--r--railties/test/railties/shared_tests.rb17
55 files changed, 1364 insertions, 518 deletions
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 54eef0473c..7f7b24804d 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,9 @@
*Rails 3.2.0 (unreleased)*
+* Updated Rails::Rack::Logger middleware to apply any tags set in config.log_tags to the newly ActiveSupport::TaggedLogging Rails.logger. This makes it easy to tag log lines with debug information like subdomain and request id -- both very helpful in debugging multi-user production applications [DHH]
+
+* Default options to `rails new` can be set in ~/.railsrc [Guillermo Iguaran]
+
* Added destroy alias to Rails engines. [Guillermo Iguaran]
* Added destroy alias for Rails command line. This allows the following: `rails d model post`. [Andrey Ognevsky]
@@ -13,7 +17,10 @@
*Rails 3.1.1
-* `rake assets:precompile` loads the application but does not initialize it.
+* Add jquery-rails to Gemfile of plugins, test/dummy app needs it. Closes #3091. [Santiago Pastorino]
+
+* Add config.assets.initialize_on_precompile which, when set to false, forces
+ `rake assets:precompile` to load the application but does not initialize it.
To the app developer, this means configuration add in
config/initializers/* will not be executed.
diff --git a/railties/README.rdoc b/railties/README.rdoc
index 95c43045b0..ae40600401 100644
--- a/railties/README.rdoc
+++ b/railties/README.rdoc
@@ -15,12 +15,21 @@ The latest version of Railties can be installed with RubyGems:
* gem install railties
-Documentation can be found at
-
-* http://api.rubyonrails.org
+Source code can be downloaded as part of the Rails project on GitHub
+* https://github.com/rails/rails/tree/master/railties
== License
Railties is released under the MIT license.
+== Support
+
+API documentation is at
+
+* http://api.rubyonrails.org
+
+Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
+
+* https://github.com/rails/rails/issues
+
diff --git a/railties/guides/code/getting_started/Gemfile b/railties/guides/code/getting_started/Gemfile
index 51774934cd..898510dcaa 100644
--- a/railties/guides/code/getting_started/Gemfile
+++ b/railties/guides/code/getting_started/Gemfile
@@ -25,8 +25,3 @@ gem 'jquery-rails'
# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'
-
-group :test do
- # Pretty printed test output
- gem 'turn', :require => false
-end
diff --git a/railties/guides/code/getting_started/config/environments/production.rb b/railties/guides/code/getting_started/config/environments/production.rb
index 6ab63d30a6..dee8acfdfe 100644
--- a/railties/guides/code/getting_started/config/environments/production.rb
+++ b/railties/guides/code/getting_started/config/environments/production.rb
@@ -33,8 +33,11 @@ Blog::Application.configure do
# See everything in the log (default is :info)
# config.log_level = :debug
+ # Prepend all log lines with the following tags
+ # config.log_tags = [ :subdomain, :uuid ]
+
# Use a different logger for distributed setups
- # config.logger = SyslogLogger.new
+ # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production
# config.cache_store = :mem_cache_store
diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile
index d8d66302fe..b34c223b31 100644
--- a/railties/guides/source/action_controller_overview.textile
+++ b/railties/guides/source/action_controller_overview.textile
@@ -166,10 +166,10 @@ h3. Session
Your application has a session for each user in which you can store small amounts of data that will be persisted between requests. The session is only available in the controller and the view and can use one of a number of different storage mechanisms:
-* CookieStore - Stores everything on the client.
-* DRbStore - Stores the data on a DRb server.
-* MemCacheStore - Stores the data in a memcache.
-* ActiveRecordStore - Stores the data in a database using Active Record.
+* ActionDispatch::Session::CookieStore - Stores everything on the client.
+* ActiveRecord::SessionStore - Stores the data in a database using Active Record.
+* ActionDispatch::Session::CacheStore - Stores the data in the Rails cache.
+* ActionDispatch::Session::MemCacheStore - Stores the data in a memcached cluster (this is a legacy implementation; consider using CacheStore instead).
All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
@@ -177,6 +177,8 @@ For most stores this ID is used to look up the session data on the server, e.g.
The CookieStore can store around 4kB of data -- much less than the others -- but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error.
+If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using ActionDispatch::Session::CacheStore. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time.
+
Read more about session storage in the "Security Guide":security.html.
If you need a different session storage mechanism, you can change it in the +config/initializers/session_store.rb+ file:
@@ -796,7 +798,7 @@ NOTE: Certain exceptions are only rescuable from the +ApplicationController+ cla
h3. Force HTTPS protocol
-Sometime you might want to force a particular controller to only be accessible via an HTTPS protocol for security reason. Since Rails 3.1 you can now use +force_ssl+ method in your controller to enforce that:
+Sometime you might want to force a particular controller to only be accessible via an HTTPS protocol for security reasons. Since Rails 3.1 you can now use +force_ssl+ method in your controller to enforce that:
<ruby>
class DinnerController
diff --git a/railties/guides/source/active_record_basics.textile b/railties/guides/source/active_record_basics.textile
index cab8c80866..66ad7b0255 100644
--- a/railties/guides/source/active_record_basics.textile
+++ b/railties/guides/source/active_record_basics.textile
@@ -38,47 +38,48 @@ When writing applications using other programming languages or frameworks, it ma
h4. Naming Conventions
-By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the camelCase form, while the table name must contain the words separated by underscores. Examples:
+By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the CamelCase form, while the table name must contain the words separated by underscores. Examples:
-* Database Table - Plural with underscores separating words (e.g., book_clubs)
-* Model Class - Singular with the first letter of each word capitalized (e.g., BookClub)
+* Database Table - Plural with underscores separating words (e.g., +book_clubs+)
+* Model Class - Singular with the first letter of each word capitalized (e.g., +BookClub+)
|_.Model / Class |_.Table / Schema |
-|Post |posts|
-|LineItem |line_items|
-|Deer |deer|
-|Mouse |mice|
-|Person |people|
+|+Post+ |+posts+|
+|+LineItem+ |+line_items+|
+|+Deer+ |+deer+|
+|+Mouse+ |+mice+|
+|+Person+ |+people+|
h4. Schema Conventions
Active Record uses naming conventions for the columns in database tables, depending on the purpose of these columns.
-* *Foreign keys* - These fields should be named following the pattern table_id (e.g., item_id, order_id). These are the fields that Active Record will look for when you create associations between your models.
-* *Primary keys* - By default, Active Record will use an integer column named "id" as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created.
+* *Foreign keys* - These fields should be named following the pattern +singularized_table_name_id+ (e.g., +item_id+, +order_id+). These are the fields that Active Record will look for when you create associations between your models.
+* *Primary keys* - By default, Active Record will use an integer column named +id+ as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created.
There are also some optional column names that will create additional features to Active Record instances:
-* *created_at* - Automatically gets set to the current date and time when the record is first created.
-* *created_on* - Automatically gets set to the current date when the record is first created.
-* *updated_at* - Automatically gets set to the current date and time whenever the record is updated.
-* *updated_on* - Automatically gets set to the current date whenever the record is updated.
-* *lock_version* - Adds "optimistic locking":http://api.rubyonrails.org/classes/ActiveRecord/Locking.html to a model.
-* *type* - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.org/classes/ActiveRecord/Base.html
-* *(table_name)_count* - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post.
+* +created_at+ - Automatically gets set to the current date and time when the record is first created.
+* +created_on+ - Automatically gets set to the current date when the record is first created.
+* +updated_at+ - Automatically gets set to the current date and time whenever the record is updated.
+* +updated_on+ - Automatically gets set to the current date whenever the record is updated.
+* +lock_version+ - Adds "optimistic locking":http://api.rubyonrails.org/classes/ActiveRecord/Locking.html to a model.
+* +type+ - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.org/classes/ActiveRecord/Base.html
+* +(table_name)_count+ - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post.
-NOTE: While these column names are optional they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, "type" is a reserved keyword used to designate a table using Single Table Inheritance. If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling.
+NOTE: While these column names are optional, they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, +type+ is a reserved keyword used to designate a table using Single Table Inheritance (STI). If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling.
h3. Creating Active Record Models
-It's very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go:
+It is very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go:
<ruby>
-class Product < ActiveRecord::Base; end
+class Product < ActiveRecord::Base
+end
</ruby>
-This will create a +Product+ model, mapped to a *products* table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. So, suppose that the *products* table was created using an SQL sentence like:
+This will create a +Product+ model, mapped to a +products+ table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. Suppose that the +products+ table was created using an SQL sentence like:
<sql>
CREATE TABLE products (
@@ -126,21 +127,21 @@ class Product < ActiveRecord::Base
end
</ruby>
-h3. Reading and Writing Data
+h3. CRUD: Reading and Writing Data
CRUD is an acronym for the four verbs we use to operate on data: *C*reate, *R*ead, *U*pdate and *D*elete. Active Record automatically creates methods to allow an application to read and manipulate data stored within its tables.
h4. Create
-Active Record objects can be created from a hash, a block or have its attributes manually set after creation. The _new_ method will return a new object while _create_ will return the object and save it to the database.
+Active Record objects can be created from a hash, a block or have their attributes manually set after creation. The +new+ method will return a new object while +create+ will return the object and save it to the database.
-For example, given a model +User+ with attributes of +name+ and +occupation+, the _create_ method call will create and save a new record into the database:
+For example, given a model +User+ with attributes of +name+ and +occupation+, the +create+ method call will create and save a new record into the database:
<ruby>
user = User.create(:name => "David", :occupation => "Code Artist")
</ruby>
-Using the _new_ method, an object can be created without being saved:
+Using the +new+ method, an object can be created without being saved:
<ruby>
user = User.new
@@ -148,9 +149,9 @@ Using the _new_ method, an object can be created without being saved:
user.occupation = "Code Artist"
</ruby>
-A call to _user.save_ will commit the record to the database.
+A call to +user.save+ will commit the record to the database.
-Finally, passing a block to either create or new will return a new User object:
+Finally, if a block is provided, both +create+ and +new+ will yield the new object to that block for initialization:
<ruby>
user = User.new do |u|
@@ -164,7 +165,7 @@ h4. Read
Active Record provides a rich API for accessing data within a database. Below are a few examples of different data access methods provided by Active Record.
<ruby>
- # return all records
+ # return array with all records
users = User.all
</ruby>
diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile
index 96f91cfef6..2e1f89cb78 100644
--- a/railties/guides/source/active_record_querying.textile
+++ b/railties/guides/source/active_record_querying.textile
@@ -13,7 +13,7 @@ endprologue.
WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in other versions of Rails.
-If you're used to using raw SQL to find database records then, generally, you will find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases.
+If you're used to using raw SQL to find database records, then you will generally find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases.
Code examples throughout this guide will refer to one or more of the following models:
@@ -69,28 +69,28 @@ The methods are:
All of the above methods return an instance of <tt>ActiveRecord::Relation</tt>.
-Primary operation of <tt>Model.find(options)</tt> can be summarized as:
+The primary operation of <tt>Model.find(options)</tt> can be summarized as:
* Convert the supplied options to an equivalent SQL query.
* Fire the SQL query and retrieve the corresponding results from the database.
* Instantiate the equivalent Ruby object of the appropriate model for every resulting row.
-* Run +after_find+ callbacks if any.
+* Run +after_find+ callbacks, if any.
h4. Retrieving a Single Object
-Active Record lets you retrieve a single object using five different ways.
+Active Record provides five different ways of retrieving a single object.
h5. Using a Primary Key
-Using <tt>Model.find(primary_key)</tt>, you can retrieve the object corresponding to the supplied _primary key_ and matching the supplied options (if any). For example:
+Using <tt>Model.find(primary_key)</tt>, you can retrieve the object corresponding to the specified _primary key_ that matches any supplied options. For example:
<ruby>
# Find the client with primary key (id) 10.
client = Client.find(10)
-=> #<Client id: 10, first_name: => "Ryan">
+# => #<Client id: 10, first_name: "Ryan">
</ruby>
-SQL equivalent of the above is:
+The SQL equivalent of the above is:
<sql>
SELECT * FROM clients WHERE (clients.id = 10)
@@ -100,14 +100,14 @@ SELECT * FROM clients WHERE (clients.id = 10)
h5. +first+
-<tt>Model.first</tt> finds the first record matched by the supplied options. For example:
+<tt>Model.first</tt> finds the first record matched by the supplied options, if any. For example:
<ruby>
client = Client.first
-=> #<Client id: 1, first_name: "Lifo">
+# => #<Client id: 1, first_name: "Lifo">
</ruby>
-SQL equivalent of the above is:
+The SQL equivalent of the above is:
<sql>
SELECT * FROM clients LIMIT 1
@@ -121,10 +121,10 @@ h5. +last+
<ruby>
client = Client.last
-=> #<Client id: 221, first_name: "Russel">
+# => #<Client id: 221, first_name: "Russel">
</ruby>
-SQL equivalent of the above is:
+The SQL equivalent of the above is:
<sql>
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
@@ -138,10 +138,10 @@ h5(#first_1). +first!+
<ruby>
client = Client.first!
-=> #<Client id: 1, first_name: "Lifo">
+# => #<Client id: 1, first_name: "Lifo">
</ruby>
-SQL equivalent of the above is:
+The SQL equivalent of the above is:
<sql>
SELECT * FROM clients LIMIT 1
@@ -155,10 +155,10 @@ h5(#last_1). +last!+
<ruby>
client = Client.last!
-=> #<Client id: 221, first_name: "Russel">
+# => #<Client id: 221, first_name: "Russel">
</ruby>
-SQL equivalent of the above is:
+The SQL equivalent of the above is:
<sql>
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
@@ -170,15 +170,15 @@ h4. Retrieving Multiple Objects
h5. Using Multiple Primary Keys
-<tt>Model.find(array_of_primary_key)</tt> also accepts an array of _primary keys_. An array of all the matching records for the supplied _primary keys_ is returned. For example:
+<tt>Model.find(array_of_primary_key)</tt> accepts an array of _primary keys_, returning an array containing all of the matching records for the supplied _primary keys_. For example:
<ruby>
# Find the clients with primary keys 1 and 10.
-client = Client.find(1, 10) # Or even Client.find([1, 10])
-=> [#<Client id: 1, first_name: => "Lifo">, #<Client id: 10, first_name: => "Ryan">]
+client = Client.find([1, 10]) # Or even Client.find(1, 10)
+# => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">]
</ruby>
-SQL equivalent of the above is:
+The SQL equivalent of the above is:
<sql>
SELECT * FROM clients WHERE (clients.id IN (1,10))
@@ -188,24 +188,26 @@ WARNING: <tt>Model.find(array_of_primary_key)</tt> will raise an +ActiveRecord::
h4. Retrieving Multiple Objects in Batches
-Sometimes you need to iterate over a large set of records. For example to send a newsletter to all users, to export some data, etc.
+We often need to iterate over a large set of records, as when we send a newsletter to a large set of users, or when we export data.
-The following may seem very straight forward at first:
+This may appear straightforward:
<ruby>
-# Very inefficient when users table has thousands of rows.
+# This is very inefficient when the users table has thousands of rows.
User.all.each do |user|
NewsLetter.weekly_deliver(user)
end
</ruby>
-But if the total number of rows in the table is very large, the above approach may vary from being under performant to just plain impossible.
+But this approach becomes increasingly impractical as the table size increases, since +User.all.each+ instructs Active Record to fetch _the entire table_ in a single pass, build a model object per row, and then keep the entire array of model objects in memory. Indeed, if we have a large number of records, the entire collection may exceed the amount of memory available.
-This is because +User.all.each+ makes Active Record fetch _the entire table_, build a model object per row, and keep the entire array in the memory. Sometimes that is just too many objects and demands too much memory.
+Rails provides two methods that address this problem by dividing records into memory-friendly batches for processing. The first method, +find_each+, retrieves a batch of records and then yields _each_ record to the block individually as a model. The second method, +find_in_batches+, retrieves a batch of records and then yields _the entire batch_ to the block as an array of models.
+
+TIP: The +find_each+ and +find_in_batches+ methods are intended for use in the batch processing of a large number of records that wouldn't fit in memory all at once. If you just need to loop over a thousand records the regular find methods are the preferred option.
h5. +find_each+
-To efficiently iterate over a large table, Active Record provides a batch finder method called +find_each+:
+The +find_each+ method retrieves a batch of records and then yields _each_ record to the block individually as a model. In the following example, +find_each+ will retrieve 1000 records (the current default for both +find_each+ and +find_in_batches+) and then yield each record individually to the block as a model. This process is repeated until all of the records have been processed:
<ruby>
User.find_each do |user|
@@ -213,11 +215,15 @@ User.find_each do |user|
end
</ruby>
-*Configuring the batch size*
+h6. Options for +find_each+
+
+The +find_each+ method accepts most of the options allowed by the regular +find+ method, except for +:order+ and +:limit+, which are reserved for internal use by +find_each+.
+
+Two additional options, +:batch_size+ and +:start+, are available as well.
-Behind the scenes +find_each+ fetches rows in batches of +1000+ and yields them one by one. The size of the underlying batches is configurable via the +:batch_size+ option.
+*+:batch_size+*
-To fetch +User+ records in batch size of +5000+:
+The +:batch_size+ option allows you to specify the number of records to be retrieved in each batch, before being passed individually to the block. For example, to retrieve records in batches of 5000:
<ruby>
User.find_each(:batch_size => 5000) do |user|
@@ -225,34 +231,38 @@ User.find_each(:batch_size => 5000) do |user|
end
</ruby>
-*Starting batch find from a specific primary key*
+*+:start+*
-Records are fetched in ascending order on the primary key, which must be an integer. The +:start+ option allows you to configure the first ID of the sequence if the lowest is not the one you need. This may be useful for example to be able to resume an interrupted batch process if it saves the last processed ID as a checkpoint.
+By default, records are fetched in ascending order of the primary key, which must be an integer. The +:start+ option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint.
-To send newsletters only to users with the primary key starting from +2000+:
+For example, to send newsletters only to users with the primary key starting from 2000, and to retrieve them in batches of 5000:
<ruby>
-User.find_each(:batch_size => 5000, :start => 2000) do |user|
+User.find_each(:start => 2000, :batch_size => 5000) do |user|
NewsLetter.weekly_deliver(user)
end
</ruby>
-*Additional options*
+Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate <tt>:start</tt> option on each worker.
-+find_each+ accepts the same options as the regular +find+ method. However, +:order+ and +:limit+ are needed internally and hence not allowed to be passed explicitly.
+NOTE: The +:include+ option allows you to name associations that should be loaded alongside with the models.
h5. +find_in_batches+
-You can also work by chunks instead of row by row using +find_in_batches+. This method is analogous to +find_each+, but it yields arrays of models instead:
+The +find_in_batches+ method is similar to +find_each+, since both retrieve batches of records. The difference is that +find_in_batches+ yields _batches_ to the block as an array of models, instead of individually. The following example will yield to the supplied block an array of up to 1000 invoices at a time, with the final block containing any remaining invoices:
<ruby>
-# Works in chunks of 1000 invoices at a time.
+# Give add_invoices an array of 1000 invoices at a time
Invoice.find_in_batches(:include => :invoice_lines) do |invoices|
export.add_invoices(invoices)
end
</ruby>
-The above will yield the supplied block with +1000+ invoices every time.
+NOTE: The +:include+ option allows you to name associations that should be loaded alongside with the models.
+
+h6. Options for +find_in_batches+
+
+The +find_in_batches+ method accepts the same +:batch_size+ and +:start+ options as +find_each+, as well as most of the options allowed by the regular +find+ method, except for +:order+ and +:limit+, which are reserved for internal use by +find_in_batches+.
h3. Conditions
@@ -266,7 +276,7 @@ WARNING: Building your own conditions as pure strings can leave you vulnerable t
h4. Array Conditions
-Now what if that number could vary, say as an argument from somewhere? The find then becomes something like:
+Now what if that number could vary, say as an argument from somewhere? The find would then take the form:
<ruby>
Client.where("orders_count = ?", params[:orders])
@@ -274,7 +284,7 @@ Client.where("orders_count = ?", params[:orders])
Active Record will go through the first element in the conditions value and any additional elements will replace the question marks +(?)+ in the first element.
-Or if you want to specify two conditions, you can do it like:
+If you want to specify multiple conditions:
<ruby>
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
@@ -282,19 +292,19 @@ Client.where("orders_count = ? AND locked = ?", params[:orders], false)
In this example, the first question mark will be replaced with the value in +params[:orders]+ and the second will be replaced with the SQL representation of +false+, which depends on the adapter.
-The reason for doing code like:
+This code is highly preferable:
<ruby>
Client.where("orders_count = ?", params[:orders])
</ruby>
-instead of:
+to this code:
<ruby>
Client.where("orders_count = #{params[:orders]}")
</ruby>
-is because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database *as-is*. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out he or she can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string.
+because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database *as-is*. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out he or she can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string.
TIP: For more information on the dangers of SQL injection, see the "Ruby on Rails Security Guide":security.html#sql-injection.
@@ -616,7 +626,7 @@ c1.first_name = "Michael"
c1.save
c2.name = "should fail"
-c2.save # Raises a ActiveRecord::StaleObjectError
+c2.save # Raises an ActiveRecord::StaleObjectError
</ruby>
You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging, or otherwise apply the business logic needed to resolve the conflict.
@@ -911,14 +921,14 @@ end
To call this +published+ scope we can call it on either the class:
<ruby>
-Post.published => [published posts]
+Post.published # => [published posts]
</ruby>
Or on an association consisting of +Post+ objects:
<ruby>
category = Category.first
-category.posts.published => [published posts belonging to this category]
+category.posts.published # => [published posts belonging to this category]
</ruby>
h4. Working with times
@@ -1014,7 +1024,7 @@ You can also use +find_last_by_*+ methods which will find the last record matchi
You can specify an exclamation point (<tt>!</tt>) on the end of the dynamic finders to get them to raise an +ActiveRecord::RecordNotFound+ error if they do not return any records, like +Client.find_by_name!("Ryan")+
-If you want to find both by name and locked, you can chain these finders together by simply typing +and+ between the fields. For example, +Client.find_by_first_name_and_locked("Ryan", true)+.
+If you want to find both by name and locked, you can chain these finders together by simply typing "+and+" between the fields. For example, +Client.find_by_first_name_and_locked("Ryan", true)+.
WARNING: Up to and including Rails 3.1, when the number of arguments passed to a dynamic finder method is lesser than the number of fields, say <tt>Client.find_by_name_and_locked("Ryan")</tt>, the behavior is to pass +nil+ as the missing argument. This is *unintentional* and this behavior will be changed in Rails 3.2 to throw an +ArgumentError+.
@@ -1030,7 +1040,7 @@ Suppose you want to find a client named 'Andy', and if there's none, create one
<ruby>
Client.where(:first_name => 'Andy').first_or_create(:locked => false)
-# => <Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
+# => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
</ruby>
The SQL generated by this method looks like this:
diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile
index 5c3aae2955..665e7f9ccc 100644
--- a/railties/guides/source/active_record_validations_callbacks.textile
+++ b/railties/guides/source/active_record_validations_callbacks.textile
@@ -28,7 +28,7 @@ h4. Why Use Validations?
Validations are used to ensure that only valid data is saved into your database. For example, it may be important to your application to ensure that every user provides a valid email address and mailing address.
-There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations.
+There are several ways to validate data before it is saved into your database, including native database constraints, client-side validations, controller-level validations, and model-level validations:
* Database constraints and/or stored procedures make the validation mechanisms database-dependent and can make testing and maintenance more difficult. However, if your database is used by other applications, it may be a good idea to use some constraints at the database level. Additionally, database-level validations can safely handle some things (such as uniqueness in heavily-used tables) that can be difficult to implement otherwise.
* Client-side validations can be useful, but are generally unreliable if used alone. If they are implemented using JavaScript, they may be bypassed if JavaScript is turned off in the user's browser. However, if combined with other techniques, client-side validation can be a convenient way to provide users with immediate feedback as they use your site.
@@ -46,7 +46,7 @@ end
We can see how it works by looking at some +rails console+ output:
-<shell>
+<ruby>
>> p = Person.new(:name => "John Doe")
=> #<Person id: nil, name: "John Doe", created_at: nil, :updated_at: nil>
>> p.new_record?
@@ -55,7 +55,7 @@ We can see how it works by looking at some +rails console+ output:
=> true
>> p.new_record?
=> false
-</shell>
+</ruby>
Creating and saving a new record will send an SQL +INSERT+ operation to the database. Updating an existing record will send an SQL +UPDATE+ operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the +INSERT+ or +UPDATE+ operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated.
@@ -94,7 +94,7 @@ Note that +save+ also has the ability to skip validations if passed +:validate =
h4. +valid?+ and +invalid?+
-To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were added to the object, and false otherwise.
+To verify whether or not an object is valid, Rails uses the +valid?+ method. You can also use this method on your own. +valid?+ triggers your validations and returns true if no errors were found in the object, and false otherwise.
<ruby>
class Person < ActiveRecord::Base
@@ -105,7 +105,7 @@ Person.create(:name => "John Doe").valid? # => true
Person.create(:name => nil).valid? # => false
</ruby>
-When Active Record is performing validations, any errors found can be accessed through the +errors+ instance method. By definition an object is valid if this collection is empty after running validations.
+After Active Record has performed validations, any errors found can be accessed through the +errors+ instance method, which returns a collection of errors. By definition, an object is valid if this collection is empty after running validations.
Note that an object instantiated with +new+ will not report errors even if it's technically invalid, because validations are not run when using +new+.
@@ -139,7 +139,7 @@ end
=> ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
</ruby>
-+invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations and returns true if any errors were added to the object, and false otherwise.
++invalid?+ is simply the inverse of +valid?+. +invalid?+ triggers your validations, returning true if any errors were found in the object, and false otherwise.
h4(#validations_overview-errors). +errors[]+
@@ -160,7 +160,7 @@ We'll cover validation errors in greater depth in the "Working with Validation E
h3. Validation Helpers
-Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the field being validated.
+Active Record offers many pre-defined validation helpers that you can use directly inside your class definitions. These helpers provide common validation rules. Every time a validation fails, an error message is added to the object's +errors+ collection, and this message is associated with the attribute being validated.
Each helper accepts an arbitrary number of attribute names, so with a single line of code you can add the same kind of validation to several attributes.
@@ -428,6 +428,8 @@ class GoodnessValidator < ActiveModel::Validator
end
</ruby>
+NOTE: Errors added to +record.errors[:base]+ relate to the state of the record as a whole, and not to a specific attribute.
+
The +validates_with+ helper takes a class, or a list of classes to use for validation. There is no default error message for +validates_with+. You must manually add errors to the record's errors collection in the validator class.
To implement the validate method, you must have a +record+ parameter defined, which is the record to be validated.
@@ -454,13 +456,13 @@ This helper validates attributes against a block. It doesn't have a predefined v
<ruby>
class Person < ActiveRecord::Base
- validates_each :name, :surname do |model, attr, value|
- model.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/
+ validates_each :name, :surname do |record, attr, value|
+ record.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/
end
end
</ruby>
-The block receives the model, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you can add an error message to the model, therefore making it invalid.
+The block receives the record, the attribute's name and the attribute's value. You can do anything you like to check for valid data within the block. If your validation fails, you should add an error message to the model, therefore making it invalid.
h3. Common Validation Options
@@ -580,7 +582,7 @@ Custom validators are classes that extend <tt>ActiveModel::Validator</tt>. These
<ruby>
class MyValidator < ActiveModel::Validator
def validate(record)
- if record.name.starts_with? 'X'
+ unless record.name.starts_with? 'X'
record.errors[:name] << 'Need a name starting with X please!'
end
end
@@ -661,7 +663,7 @@ The following is a list of the most commonly used methods. Please refer to the +
h4(#working_with_validation_errors-errors). +errors+
-Returns an OrderedHash with all errors. Each key is the attribute name and the value is an array of strings with all errors.
+Returns an instance of the class +ActiveModel::Errors+ (which behaves like an ordered hash) containing all errors. Each key is the attribute name and the value is an array of strings with all errors.
<ruby>
class Person < ActiveRecord::Base
@@ -741,7 +743,7 @@ Another way to do this is using +[]=+ setter
h4. +errors[:base]+
-You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to the array and uses it as the error message.
+You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since +errors[:base]+ is an array, you can simply add a string to it and it will be used as an error message.
<ruby>
class Person < ActiveRecord::Base
@@ -785,7 +787,7 @@ end
person = Person.new
person.valid? # => false
-person.errors.size # => 3
+person.errors.size # => 2
person = Person.new(:name => "Andrea", :email => "andrea@example.com")
person.valid? # => true
@@ -794,7 +796,7 @@ person.errors.size # => 0
h3. Displaying Validation Errors in the View
-Rails maintains an official plugin that provides helpers to display the error messages of your models in your view templates. You can install it as a plugin or as a Gem.
+Rails maintains an official plugin, DynamicForm, that provides helpers to display the error messages of your models in your view templates. You can install it as a plugin or as a Gem.
h4. Installing as a plugin
@@ -810,7 +812,7 @@ Add this line in your Gemfile:
gem "dynamic_form"
</ruby>
-Now you will have access to these two methods in your view templates.
+Now you will have access to the two helper methods +error_messages+ and +error_messages_for+ in your view templates.
h4. +error_messages+ and +error_messages_for+
@@ -840,11 +842,13 @@ end
<% end %>
</erb>
-To get the idea, if you submit the form with empty fields you typically get this back, though styles are indeed missing by default:
+If you submit the form with empty fields, the result will be similar to the one shown below:
!images/error_messages.png(Error messages)!
-You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It's very similar to the previous example and will achieve exactly the same result.
+NOTE: The appearance of the generated HTML will be different from the one shown, unless you have used scaffolding. See "Customizing the Error Messages CSS":#customizing-error-messages-css.
+
+You can also use the +error_messages_for+ helper to display the error messages of a model assigned to a view template. It is very similar to the previous example and will achieve exactly the same result.
<erb>
<%= error_messages_for :product %>
@@ -852,7 +856,7 @@ You can also use the +error_messages_for+ helper to display the error messages o
The displayed text for each error message will always be formed by the capitalized name of the attribute that holds the error, followed by the error message itself.
-Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, changing the header text, the message below the header text and the tag used for the element that defines the header.
+Both the +form.error_messages+ and the +error_messages_for+ helpers accept options that let you customize the +div+ element that holds the messages, change the header text, change the message below the header, and specify the tag used for the header element. For example,
<erb>
<%= f.error_messages :header_message => "Invalid product!",
@@ -860,23 +864,23 @@ Both the +form.error_messages+ and the +error_messages_for+ helpers accept optio
:header_tag => :h3 %>
</erb>
-Which results in the following content:
+results in:
!images/customized_error_messages.png(Customized error messages)!
-If you pass +nil+ to any of these options, it will get rid of the respective section of the +div+.
+If you pass +nil+ in any of these options, the corresponding section of the +div+ will be discarded.
-h4. Customizing the Error Messages CSS
+h4(#customizing-error-messages-css). Customizing the Error Messages CSS
-The selectors to customize the style of error messages are:
+The selectors used to customize the style of error messages are:
* +.field_with_errors+ - Style for the form fields and labels with errors.
-* +#errorExplanation+ - Style for the +div+ element with the error messages.
-* +#errorExplanation h2+ - Style for the header of the +div+ element.
-* +#errorExplanation p+ - Style for the paragraph that holds the message that appears right below the header of the +div+ element.
-* +#errorExplanation ul li+ - Style for the list items with individual error messages.
+* +#error_explanation+ - Style for the +div+ element with the error messages.
+* +#error_explanation h2+ - Style for the header of the +div+ element.
+* +#error_explanation p+ - Style for the paragraph holding the message that appears right below the header of the +div+ element.
+* +#error_explanation ul li+ - Style for the list items with individual error messages.
-Scaffolding for example generates +app/assets/stylesheets/scaffold.css.scss+, which later compiles to +app/assets/stylesheets/scaffold.css+ and defines the red-based style you saw above.
+If scaffolding was used, file +app/assets/stylesheets/scaffolds.css.scss+ will have been generated automatically. This file defines the red-based styles you saw in the examples above.
The name of the class and the id can be changed with the +:class+ and +:id+ options, accepted by both helpers.
@@ -889,7 +893,7 @@ The way form fields with errors are treated is defined by +ActionView::Base.fiel
* A string with the HTML tag
* An instance of +ActionView::Helpers::InstanceTag+.
-Here is a simple example where we change the Rails behavior to always display the error messages in front of each of the form fields with errors. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want.
+Below is a simple example where we change the Rails behavior to always display the error messages in front of each of the form fields in error. The error messages will be enclosed by a +span+ element with a +validation-error+ CSS class. There will be no +div+ element enclosing the +input+ element, so we get rid of that red border around the text field. You can use the +validation-error+ CSS class to style it anyway you want.
<ruby>
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
@@ -903,17 +907,17 @@ ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
end
</ruby>
-This will result in something like the following:
+The result looks like the following:
!images/validation_error_messages.png(Validation error messages)!
h3. Callbacks Overview
-Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it's possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.
+Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.
h4. Callback Registration
-In order to use the available callbacks, you need to register them. You can do that by implementing them as ordinary methods, and then using a macro-style class method to register them as callbacks.
+In order to use the available callbacks, you need to register them. You can implement the callbacks as ordinary methods and use a macro-style class method to register them as callbacks:
<ruby>
class User < ActiveRecord::Base
@@ -930,7 +934,7 @@ class User < ActiveRecord::Base
end
</ruby>
-The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in just one line.
+The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in a single line:
<ruby>
class User < ActiveRecord::Base
@@ -942,7 +946,7 @@ class User < ActiveRecord::Base
end
</ruby>
-It's considered good practice to declare callback methods as being protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation.
+It is considered good practice to declare callback methods as protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation.
h3. Available Callbacks
@@ -982,7 +986,7 @@ The +after_initialize+ callback will be called whenever an Active Record object
The +after_find+ callback will be called whenever Active Record loads a record from the database. +after_find+ is called before +after_initialize+ if both are defined.
-The +after_initialize+ and +after_find+ callbacks are a bit different from the others. They have no +before_*+ counterparts, and the only way to register them is by defining them as regular methods. If you try to register +after_initialize+ or +after_find+ using macro-style class methods, they will just be ignored. This behavior is due to performance reasons, since +after_initialize+ and +after_find+ will both be called for each record found in the database, significantly slowing down the queries.
+The +after_initialize+ and +after_find+ callbacks are a bit different from the others. They have no +before_*+ counterparts, and they are registered simply by defining them as regular methods with predefined names. If you try to register +after_initialize+ or +after_find+ using macro-style class methods, they will just be ignored. This behavior is due to performance reasons, since +after_initialize+ and +after_find+ will both be called for each record found in the database, which would otherwise significantly slow down the queries.
<ruby>
class User < ActiveRecord::Base
@@ -1039,7 +1043,7 @@ The +after_initialize+ callback is triggered every time a new object of the clas
h3. Skipping Callbacks
-Just as with validations, it's also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data.
+Just as with validations, it is also possible to skip callbacks. These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data.
* +decrement+
* +decrement_counter+
@@ -1058,13 +1062,13 @@ h3. Halting Execution
As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model's validations, the registered callbacks, and the database operation to be executed.
-The whole callback chain is wrapped in a transaction. If any <em>before</em> callback method returns exactly +false+ or raises an exception the execution chain gets halted and a ROLLBACK is issued; <em>after</em> callbacks can only accomplish that by raising an exception.
+The whole callback chain is wrapped in a transaction. If any <em>before</em> callback method returns exactly +false+ or raises an exception, the execution chain gets halted and a ROLLBACK is issued; <em>after</em> callbacks can only accomplish that by raising an exception.
-WARNING. Raising an arbitrary exception may break code that expects +save+ and friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised.
+WARNING. Raising an arbitrary exception may break code that expects +save+ and its friends not to fail like that. The +ActiveRecord::Rollback+ exception is thought precisely to tell Active Record a rollback is going on. That one is internally captured but not reraised.
h3. Relational Callbacks
-Callbacks work through model relationships, and can even be defined by them. Let's take an example where a user has many posts. In our example, a user's posts should be destroyed if the user is destroyed. So, we'll add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model.
+Callbacks work through model relationships, and can even be defined by them. Suppose an example where a user has many posts. A user's posts should be destroyed if the user is destroyed. Let's add an +after_destroy+ callback to the +User+ model by way of its relationship to the +Post+ model:
<ruby>
class User < ActiveRecord::Base
@@ -1090,11 +1094,11 @@ Post destroyed
h3. Conditional Callbacks
-Like in validations, we can also make our callbacks conditional, calling them only when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the callback *should* get called. If you want to specify when the callback *should not* be called, then you may use the +:unless+ option.
+As with validations, we can also make the calling of a callback method conditional on the satisfaction of a given predicate. We can do this using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify under which conditions the callback *should* be called. If you want to specify the conditions under which the callback *should not* be called, then you may use the +:unless+ option.
-h4. Using +:if+ and +:unless+ with a Symbol
+h4. Using +:if+ and +:unless+ with a +Symbol+
-You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a method that will get called right before the callback. When using the +:if+ option, the callback won't be executed if the method returns false; when using the +:unless+ option, the callback won't be executed if the method returns true. This is the most common option. Using this form of registration it's also possible to register several different methods that should be called to check if the callback should be executed.
+You can associate the +:if+ and +:unless+ options with a symbol corresponding to the name of a predicate method that will get called right before the callback. When using the +:if+ option, the callback won't be executed if the predicate method returns false; when using the +:unless+ option, the callback won't be executed if the predicate method returns true. This is the most common option. Using this form of registration it is also possible to register several different predicates that should be called to check if the callback should be executed.
<ruby>
class Order < ActiveRecord::Base
@@ -1104,7 +1108,7 @@ end
h4. Using +:if+ and +:unless+ with a String
-You can also use a string that will be evaluated using +eval+ and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition.
+You can also use a string that will be evaluated using +eval+ and hence needs to contain valid Ruby code. You should use this option only when the string represents a really short condition:
<ruby>
class Order < ActiveRecord::Base
@@ -1112,9 +1116,9 @@ class Order < ActiveRecord::Base
end
</ruby>
-h4. Using +:if+ and +:unless+ with a Proc
+h4. Using +:if+ and +:unless+ with a +Proc+
-Finally, it's possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners.
+Finally, it is possible to associate +:if+ and +:unless+ with a +Proc+ object. This option is best suited when writing short validation methods, usually one-liners:
<ruby>
class Order < ActiveRecord::Base
@@ -1125,7 +1129,7 @@ end
h4. Multiple Conditions for Callbacks
-When writing conditional callbacks, it's possible to mix both +:if+ and +:unless+ in the same callback declaration.
+When writing conditional callbacks, it is possible to mix both +:if+ and +:unless+ in the same callback declaration:
<ruby>
class Comment < ActiveRecord::Base
@@ -1138,7 +1142,7 @@ h3. Callback Classes
Sometimes the callback methods that you'll write will be useful enough to be reused by other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them.
-Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model.
+Here's an example where we create a class with an +after_destroy+ callback for a +PictureFile+ model:
<ruby>
class PictureFileCallbacks
@@ -1150,7 +1154,7 @@ class PictureFileCallbacks
end
</ruby>
-When declared inside a class the callback method will receive the model object as a parameter. We can now use it this way:
+When declared inside a class, as above, the callback methods will receive the model object as a parameter. We can now use the callback class in the model:
<ruby>
class PictureFile < ActiveRecord::Base
@@ -1158,7 +1162,7 @@ class PictureFile < ActiveRecord::Base
end
</ruby>
-Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. Sometimes it will make more sense to have it as a class method.
+Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we declared our callback as an instance method. This is particularly useful if the callbacks make use of the state of the instantiated object. Often, however, it will make more sense to declare the callbacks as class methods:
<ruby>
class PictureFileCallbacks
@@ -1182,16 +1186,25 @@ You can declare as many callbacks as you want inside your callback classes.
h3. Observers
-Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality outside of a model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead.
+Observers are similar to callbacks, but with important differences. Whereas callbacks can pollute a model with code that isn't directly related to its purpose, observers allow you to add the same functionality without changing the code of the model. For example, it could be argued that a +User+ model should not include code to send registration confirmation emails. Whenever you use callbacks with code that isn't directly related to your model, you may want to consider creating an observer instead.
h4. Creating Observers
-For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we could create an observer to contain this functionality.
+For example, imagine a +User+ model where we want to send an email every time a new user is created. Because sending emails is not directly related to our model's purpose, we should create an observer to contain the code implementing this functionality.
<shell>
$ rails generate observer User
</shell>
+generates +app/models/user_observer.rb+ containing the observer class +UserObserver+:
+
+<ruby>
+class UserObserver < ActiveRecord::Observer
+end
+</ruby>
+
+You may now add methods to be called at the desired occasions:
+
<ruby>
class UserObserver < ActiveRecord::Observer
def after_create(model)
@@ -1207,7 +1220,7 @@ h4. Registering Observers
Observers are conventionally placed inside of your +app/models+ directory and registered in your application's +config/application.rb+ file. For example, the +UserObserver+ above would be saved as +app/models/user_observer.rb+ and registered in +config/application.rb+ this way:
<ruby>
-# Activate observers that should always be running
+# Activate observers that should always be running.
config.active_record.observers = :user_observer
</ruby>
@@ -1215,7 +1228,7 @@ As usual, settings in +config/environments+ take precedence over those in +confi
h4. Sharing Observers
-By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behavior to more than one model, and so it's possible to manually specify the models that our observer should observe.
+By default, Rails will simply strip "Observer" from an observer's name to find the model it should observe. However, observers can also be used to add behavior to more than one model, and thus it is possible to explicitly specify the models that our observer should observe:
<ruby>
class MailerObserver < ActiveRecord::Observer
@@ -1227,10 +1240,10 @@ class MailerObserver < ActiveRecord::Observer
end
</ruby>
-In this example, the +after_create+ method would be called whenever a +Registration+ or +User+ was created. Note that this new +MailerObserver+ would also need to be registered in +config/application.rb+ in order to take effect.
+In this example, the +after_create+ method will be called whenever a +Registration+ or +User+ is created. Note that this new +MailerObserver+ would also need to be registered in +config/application.rb+ in order to take effect:
<ruby>
-# Activate observers that should always be running
+# Activate observers that should always be running.
config.active_record.observers = :mailer_observer
</ruby>
@@ -1238,7 +1251,7 @@ h3. Transaction Callbacks
There are two additional callbacks that are triggered by the completion of a database transaction: +after_commit+ and +after_rollback+. These callbacks are very similar to the +after_save+ callback except that they don't execute until after database changes have either been committed or rolled back. They are most useful when your active record models need to interact with external systems which are not part of the database transaction.
-Consider, for example, the previous example where the +PictureFile+ model needs to delete a file after a record is destroyed. If anything raises an exception after the +after_destroy+ callback is called and the transaction rolls back, the file will have been deleted and the model will be left in an inconsistent state. For example, suppose that +picture_file_2+ in the code below is not valid and the +save!+ method raises an error.
+Consider, for example, the previous example where the +PictureFile+ model needs to delete a file after the corresponding record is destroyed. If anything raises an exception after the +after_destroy+ callback is called and the transaction rolls back, the file will have been deleted and the model will be left in an inconsistent state. For example, suppose that +picture_file_2+ in the code below is not valid and the +save!+ method raises an error.
<ruby>
PictureFile.transaction do
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 5aee001545..c04e49281e 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -719,9 +719,9 @@ X.local_constants # => ["X2", "X1", "Y"], assumes Ruby 1.8
X::Y.local_constants # => ["X1", "Y1"], assumes Ruby 1.8
</ruby>
-The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ returns always strings.
+The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ always returns strings.
-WARNING: This method is exact if running under Ruby 1.9. In previous versions it may miss some constants if their value in some ancestor stores the exact same object than in the receiver.
+WARNING: This method returns precise results in Ruby 1.9. In older versions of Ruby, however, it may miss some constants in case the same constant exists in the receiver module as well as in any of its ancestors and both constants point to the same object (objects are compared using +Object#object_id+).
NOTE: Defined in +active_support/core_ext/module/introspection.rb+.
@@ -1426,6 +1426,14 @@ The method +pluralize+ returns the plural of its receiver:
As the previous example shows, Active Support knows some irregular plurals and uncountable nouns. Built-in rules can be extended in +config/initializers/inflections.rb+. That file is generated by the +rails+ command and has instructions in comments.
++pluralize+ can also take an optional +count+ parameter. If <tt>count == 1</tt> the singular form will be returned. For any other value of +count+ the plural form will be returned:
+
+<ruby>
+"dude".pluralize(0) # => "dudes"
+"dude".pluralize(1) # => "dude"
+"dude".pluralize(2) # => "dudes"
+</ruby>
+
Active Record uses this method to compute the default table name that corresponds to a model:
<ruby>
@@ -1760,7 +1768,7 @@ h4(#string-conversions). Conversions
h5. +ord+
-Ruby 1.9 defines +ord+ to be the codepoint of the first character of the receiver. Active Support backports +ord+ for single-byte encondings like ASCII or ISO-8859-1 in Ruby 1.8:
+Ruby 1.9 defines +ord+ to be the codepoint of the first character of the receiver. Active Support backports +ord+ for single-byte encodings like ASCII or ISO-8859-1 in Ruby 1.8:
<ruby>
"a".ord # => 97
@@ -1774,7 +1782,7 @@ In Ruby 1.8 +ord+ doesn't work in general in UTF8 strings, use the multibyte sup
"à".mb_chars.ord # => 224, in UTF8
</ruby>
-Note that the 224 is different in both examples. In ISO-8859-1 "à" is represented as a single byte, 224. Its single-character representattion in UTF8 has two bytes, namely 195 and 160, but its Unicode codepoint is 224. If we call +ord+ on the UTF8 string "à" the return value will be 195 in Ruby 1.8. That is not an error, because UTF8 is unsupported, the call itself would be bogus.
+Note that the 224 is different in both examples. In ISO-8859-1 "à" is represented as a single byte, 224. Its single-character representation in UTF8 has two bytes, namely 195 and 160, but its Unicode codepoint is 224. If we call +ord+ on the UTF8 string "à" the return value will be 195 in Ruby 1.8. That is not an error, because UTF8 is unsupported, the call itself would be bogus.
INFO: +ord+ is equivalent to +getbyte(0)+.
diff --git a/railties/guides/source/ajax_on_rails.textile b/railties/guides/source/ajax_on_rails.textile
index 29d4fae888..3a0ccfe9b2 100644
--- a/railties/guides/source/ajax_on_rails.textile
+++ b/railties/guides/source/ajax_on_rails.textile
@@ -3,7 +3,7 @@ h2. AJAX on Rails
This guide covers the built-in Ajax/JavaScript functionality of Rails (and more); it will enable you to create rich and dynamic AJAX applications with ease! We will cover the following topics:
* Quick introduction to AJAX and related technologies
-* Handling JavaScript the Rails way: Rails helpers, Prototype and script.aculo.us
+* Unobtrusive JavaScript helpers with drivers for Prototype, jQuery etc
* Testing JavaScript functionality
endprologue.
@@ -26,14 +26,78 @@ How do 'standard' and AJAX requests differ, why does this matter for understandi
h3. Built-in Rails Helpers
-Rails' JavaScript framework of choice is "Prototype":http://www.prototypejs.org. Prototype is a generic-purpose JavaScript framework that aims to ease the development of dynamic web applications by offering DOM manipulation, AJAX and other JavaScript functionality ranging from utility functions to object oriented constructs. It is not specifically written for any language, so Rails provides a set of helpers to enable seamless integration of Prototype with your Rails views.
+Rails 3.1 ships with "jQuery":http://jquery.com as the default JavaScript library. The Gemfile contains <tt>gem 'jquery-rails'</tt> which makes the jQuery files available to the application automatically. This can be accessed as:
-To get access to these helpers, all you have to do is to include the prototype framework in your pages - typically in your master layout, application.html.erb - like so:
+<ruby>
+javascript_include_tag :defaults
+</ruby>
+
+h4. Examples
+
+All the remote_method helpers has been removed. To make them working with AJAX, simply pass the <tt>:remote => true</tt> option to the original non-remote method.
+
+<ruby>
+button_to "New", :action => "new", :form_class => "new-thing"
+</ruby>
+
+will produce
+
+<html>
+<form method="post" action="/controller/new" class="new-thing">
+ <div><input value="New" type="submit" /></div>
+</form>
+</html>
<ruby>
-javascript_include_tag 'prototype'
+button_to "Create", :action => "create", :remote => true, :form => { "data-type" => "json" }
</ruby>
+will produce
+
+<html>
+<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
+ <div><input value="Create" type="submit" /></div>
+</form>
+</html>
+
+<ruby>
+button_to "Delete Image", { :action => "delete", :id => @image.id },
+ :confirm => "Are you sure?", :method => :delete
+</ruby>
+
+will produce
+
+<html>
+<form method="post" action="/images/delete/1" class="button_to">
+ <div>
+ <input type="hidden" name="_method" value="delete" />
+ <input data-confirm='Are you sure?' value="Delete" type="submit" />
+ </div>
+</form>
+</html>
+
+<ruby>
+button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
+ :method => "delete", :remote => true, :disable_with => 'loading...')
+</ruby>
+
+will produce
+
+<html>
+<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
+ <div>
+ <input name='_method' value='delete' type='hidden' />
+ <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' />
+ </div>
+</form>
+</html>
+
+You can also choose to use Prototype instead of jQuery and specify the option using +-j+ switch while generating the application.
+
+<shell>
+rails new app_name -j prototype
+</shell>
+
You are ready to add some AJAX love to your Rails app!
h4. The Quintessential AJAX Rails Helper: link_to_remote
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index a0af018d30..6eb4ae49e3 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -38,7 +38,7 @@ h4. Main Features
The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser must make to render a web page.
-While Rails already has a feature to concatenate these types of assets -- by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+ --, it has a series of limitations. For example, it cannot generate the caches in advance, and it is not able to transparently include assets provided by third-party libraries.
+While Rails already has a feature to concatenate these types of assets by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+, it has a series of limitations. For example, it cannot generate the caches in advance, and it is not able to transparently include assets provided by third-party libraries.
The default behavior in Rails 3.1 and onward is to concatenate all files into one master file each for JS and CSS. However, you can separate files or groups of files if required (see below). In production, an MD5 fingerprint is inserted into each filename so that the file is cached by the web browser but can be invalidated if the fingerprint is altered.
@@ -120,7 +120,7 @@ All subdirectories that exist within these three locations are added to the sear
You can add additional (fully qualified) paths to the pipeline in +config/application.rb+. For example:
<ruby>
-config.assets.paths << "#{Rails.root}/app/assets/flash"
+config.assets.paths << Rails.root.join("app", "assets", "flash")
</ruby>
h4. Coding Links to Assets
@@ -232,7 +232,9 @@ There's also a default +app/assets/stylesheets/application.css+ file which conta
The directives that work in the JavaScript files also work in stylesheets, obviously including stylesheets rather than JavaScript files. The +require_tree+ directive here works the same way as the JavaScript one, requiring all stylesheets from the current directory.
-In this example +require_self+ is used. This puts the CSS contained within the file (if any) at the top of any other CSS in this file unless +require_self+ is specified after another +require+ directive.
+In this example +require_self+ is used. This puts the CSS contained within the file (if any) at the precise location of the +require_self+ call. If +require_self+ is called more than once, only the last call is respected.
+
+NOTE. If you want to use multiple Sass files, use the "Sass +@import+ rule":http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#import instead of the Sprockets directives. Using Sprockets directives all Sass files exist within their own scope, making variables or mixins only available within the document they were defined in.
You can have as many manifest files as you need. For example the +admin.css+ and +admin.js+ manifest could contain the JS and CSS files that are used for the admin section of an application.
@@ -346,6 +348,15 @@ The rake task is:
bundle exec rake assets:precompile
</plain>
+For faster asset precompiles, you can partially load your application by setting
++config.assets.initialize_on_precompile+ to false in +config/application.rb+, though in that case templates
+cannot see application objects or methods. *Heroku requires this to be false.*
+
+WARNING: If you set +config.assets.initialize_on_precompile+ to false, be sure to
+test +rake assets:precompile+ locally before deploying. It may expose bugs where
+your assets reference application objects or methods, since those are still
+in scope in development mode regardless of the value of this flag.
+
Capistrano (v2.8.0 and above) has a recipe to handle this in deployment. Add the following line to +Capfile+:
<erb>
@@ -389,7 +400,7 @@ This can be changed with the +config.assets.manifest+ option. A fully specified
config.assets.manifest = '/path/to/some/other/location'
</erb>
-NOTE: If there are missing precompiled files in production you will get an <tt>AssetNoPrecompiledError</tt> exception indicating the name of the missing file(s).
+NOTE: If there are missing precompiled files in production you will get an <tt>Sprockets::Helpers::RailsHelper::AssetPaths::AssetNotPrecompiledError</tt> exception indicating the name of the missing file(s).
h5. Server Configuration
@@ -427,38 +438,29 @@ location ~ ^/assets/ {
}
</plain>
-When files are precompiled, Sprockets also creates a "Gzip":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. This avoids the server having to do this for any requests; it can simply read the compressed files from disk. You must configure your server to use gzip compression and serve the compressed assets that will be stored in the +public/assets+ folder. The following configuration options can be used:
-
-For Apache:
-
-<plain>
-<LocationMatch "^/assets/.*$">
- # 2 lines to serve pre-gzipped version
- RewriteCond %{REQUEST_FILENAME}.gz -s
- RewriteRule ^(.+) $1.gz [L]
-</LocationMatch>
-
-# without these, Content-Type will be "application/x-gzip"
-<FilesMatch "^/assets/.*\.css.gz$">
- ForceType text/css
-</FilesMatch>
+When files are precompiled, Sprockets also creates a "gzipped":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. Web servers are typically configured to use a moderate compression ratio as a compromise, but since precompilation happens once Sprockets uses the maximum compression ratio, thus reducing the size of the data transfer to the minimum. One the other hand, web servers can be configured to serve compressed content directly from disk, rather than deflating non-compressed files themselves.
-<FilesMatch "^/assets/.*\.js.gz$">
- ForceType text/javascript
-</FilesMatch>
-</plain>
-
-For nginx:
+Nginx is able to do this automatically enabling +gzip_static+:
<plain>
location ~ ^/(assets)/ {
root /path/to/public;
gzip_static on; # to serve pre-gzipped version
expires max;
- add_header Cache-Control public;
+ add_header Cache-Control public;
}
</plain>
+This directive is available if the core module that provides this feature was compiled with the web server. Ubuntu packages, even +nginx-light+ have the module compiled. Otherwise, you may need to perform a manual compilation:
+
+<plain>
+./configure --with-http_gzip_static_module
+</plain>
+
+If you're compiling nginx with Phusion Passenger you'll need to pass that option when prompted.
+
+Unfortunately, a robust configuration for Apache is possible but tricky, please Google around.
+
h4. Live Compilation
In some circumstances you may wish to use live compilation. In this mode all requests for assets in the pipeline are handled by Sprockets directly.
diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile
index f5f0f9340c..6829eb8ef4 100644
--- a/railties/guides/source/association_basics.textile
+++ b/railties/guides/source/association_basics.textile
@@ -211,7 +211,7 @@ end
h4. Choosing Between +belongs_to+ and +has_one+
-If you want to set up a 1–1 relationship between two models, you'll need to add +belongs_to+ to one, and +has_one+ to the other. How do you know which is which?
+If you want to set up a one-to-one relationship between two models, you'll need to add +belongs_to+ to one, and +has_one+ to the other. How do you know which is which?
The distinction is in where you place the foreign key (it goes on the table for the class declaring the +belongs_to+ association), but you should give some thought to the actual meaning of the data as well. The +has_one+ relationship says that one of something is yours - that is, that something points back to you. For example, it makes more sense to say that a supplier owns an account than that an account owns a supplier. This suggests that the correct relationships are like this:
@@ -566,7 +566,7 @@ The <tt>build_<em>association</em></tt> method returns a new object of the assoc
h6(#belongs_to-create_association). <tt>create_<em>association</em>(attributes = {})</tt>
-The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through this object's foreign key will be set. In addition, the associated object _will_ be saved (assuming that it passes any validations).
+The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through this object's foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
<ruby>
@customer = @order.create_customer(:customer_number => 123,
@@ -576,7 +576,7 @@ The <tt>create_<em>association</em></tt> method returns a new object of the asso
h5. Options for +belongs_to+
-In many situations, you can use the default behavior of +belongs_to+ without any customization. But despite Rails' emphasis of convention over customization, you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +belongs_to+ association. For example, an association with several options might look like this:
+While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +belongs_to+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options:
<ruby>
class Order < ActiveRecord::Base
@@ -671,7 +671,7 @@ WARNING: You should not specify this option on a +belongs_to+ association that i
h6(#belongs_to-foreign_key). +:foreign_key+
-By convention, Rails guesses that the column used to hold the foreign key on this model is the name of the association with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
+By convention, Rails assumes that the column used to hold the foreign key on this model is the name of the association with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
<ruby>
class Order < ActiveRecord::Base
@@ -760,9 +760,9 @@ h6(#belongs_to-validate). +:validate+
If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved.
-h5(#belongs_to-how_to_know_whether_theres_an_associated_object). How To Know Whether There's an Associated Object?
+h5(#belongs_to-do_any_associated_objects_exist). Do Any Associated Objects Exist?
-To know whether there's and associated object just check <tt><em>association</em>.nil?</tt>:
+You can see if any associated objects exist by using the <tt><em>association</em>.nil?</tt> method:
<ruby>
if @order.customer.nil?
@@ -834,7 +834,7 @@ The <tt>build_<em>association</em></tt> method returns a new object of the assoc
h6(#has_one-create_association). <tt>create_<em>association</em>(attributes = {})</tt>
-The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through its foreign key will be set. In addition, the associated object _will_ be saved (assuming that it passes any validations).
+The <tt>create_<em>association</em></tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
<ruby>
@account = @supplier.create_account(:terms => "Net 30")
@@ -842,7 +842,7 @@ The <tt>create_<em>association</em></tt> method returns a new object of the asso
h5. Options for +has_one+
-In many situations, you can use the default behavior of +has_one+ without any customization. But despite Rails' emphasis of convention over customization, you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +has_one+ association. For example, an association with several options might look like this:
+While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +has_one+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options:
<ruby>
class Supplier < ActiveRecord::Base
@@ -902,7 +902,7 @@ If you set the +:dependent+ option to +:destroy+, then deleting this object will
h6(#has_one-foreign_key). +:foreign_key+
-By convention, Rails guesses that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
+By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
<ruby>
class Supplier < ActiveRecord::Base
@@ -954,7 +954,7 @@ The +:order+ option dictates the order in which associated objects will be recei
h6(#has_one-primary_key). +:primary_key+
-By convention, Rails guesses that the column used to hold the primary key of this model is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
+By convention, Rails assumes that the column used to hold the primary key of this model is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
h6(#has_one-readonly). +:readonly+
@@ -980,9 +980,9 @@ h6(#has_one-validate). +:validate+
If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved.
-h5(#has_one-how_to_know_whether_theres_an_associated_object). How To Know Whether There's an Associated Object?
+h5(#has_one-do_any_associated_objects_exist). Do Any Associated Objects Exist?
-To know whether there's and associated object just check <tt><em>association</em>.nil?</tt>:
+You can see if any associated objects exist by using the <tt><em>association</em>.nil?</tt> method:
<ruby>
if @supplier.account.nil?
@@ -1147,7 +1147,7 @@ The <tt><em>collection</em>.build</tt> method returns one or more new objects of
h6(#has_many-collection-create). <tt><em>collection</em>.create(attributes = {})</tt>
-The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be created, and the associated object _will_ be saved (assuming that it passes any validations).
+The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
<ruby>
@order = @customer.orders.create(:order_date => Time.now,
@@ -1156,7 +1156,7 @@ The <tt><em>collection</em>.create</tt> method returns a new object of the assoc
h5. Options for +has_many+
-In many situations, you can use the default behavior for +has_many+ without any customization. But you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +has_many+ association. For example, an association with several options might look like this:
+While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +has_many+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options:
<ruby>
class Customer < ActiveRecord::Base
@@ -1229,17 +1229,15 @@ end
If you use a hash-style +:conditions+ option, then record creation via this association will be automatically scoped using the hash. In this case, using +@customer.confirmed_orders.create+ or +@customer.confirmed_orders.build+ will create orders where the confirmed column has the value +true+.
-If you need to evaluate conditions dynamically at runtime, you could use string interpolation in single quotes:
+If you need to evaluate conditions dynamically at runtime, use a proc:
<ruby>
class Customer < ActiveRecord::Base
has_many :latest_orders, :class_name => "Order",
- :conditions => 'orders.created_at > #{10.hours.ago.to_s(:db).inspect}'
+ :conditions => proc { "orders.created_at > #{10.hours.ago.to_s(:db).inspect}" }
end
</ruby>
-Be sure to use single quotes.
-
h6(#has_many-counter_sql). +:counter_sql+
Normally Rails automatically generates the proper SQL to count the association members. With the +:counter_sql+ option, you can specify a complete SQL statement to count them yourself.
@@ -1262,7 +1260,7 @@ Normally Rails automatically generates the proper SQL to fetch the association m
h6(#has_many-foreign_key). +:foreign_key+
-By convention, Rails guesses that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
+By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
<ruby>
class Customer < ActiveRecord::Base
@@ -1345,7 +1343,7 @@ end
h6(#has_many-primary_key). +:primary_key+
-By convention, Rails guesses that the column used to hold the primary key of the association is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
+By convention, Rails assumes that the column used to hold the primary key of the association is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
h6(#has_many-readonly). +:readonly+
@@ -1551,7 +1549,7 @@ The <tt><em>collection</em>.find</tt> method finds objects within the collection
:conditions => ["created_at > ?", 2.days.ago])
</ruby>
-NOTE: Starting Rails 3, supplying options to +ActiveRecord::Base.find+ method is discouraged. Use <tt><em>collection</em>.where</tt> instead when you need to pass conditions.
+NOTE: Beginning with Rails 3, supplying options to the +ActiveRecord::Base.find+ method is discouraged. Use <tt><em>collection</em>.where</tt> instead when you need to pass conditions.
h6(#has_and_belongs_to_many-collection-where). <tt><em>collection</em>.where(...)</tt>
@@ -1576,7 +1574,7 @@ The <tt><em>collection</em>.build</tt> method returns a new object of the associ
h6(#has_and_belongs_to_many-create-attributes). <tt><em>collection</em>.create(attributes = {})</tt>
-The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and the associated object _will_ be saved (assuming that it passes any validations).
+The <tt><em>collection</em>.create</tt> method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
<ruby>
@assembly = @part.assemblies.create(
@@ -1585,7 +1583,7 @@ The <tt><em>collection</em>.create</tt> method returns a new object of the assoc
h5. Options for +has_and_belongs_to_many+
-In many situations, you can use the default behavior for +has_and_belongs_to_many+ without any customization. But you can alter that behavior in a number of ways. This section covers the options that you can pass when you create a +has_and_belongs_to_many+ association. For example, an association with several options might look like this:
+While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +has_and_belongs_to_many+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options:
<ruby>
class Parts < ActiveRecord::Base
@@ -1619,7 +1617,7 @@ The +has_and_belongs_to_many+ association supports these options:
h6(#has_and_belongs_to_many-association_foreign_key). +:association_foreign_key+
-By convention, Rails guesses that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix +_id+ added. The +:association_foreign_key+ option lets you set the name of the foreign key directly:
+By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix +_id+ added. The +:association_foreign_key+ option lets you set the name of the foreign key directly:
TIP: The +:foreign_key+ and +:association_foreign_key+ options are useful when setting up a many-to-many self-join. For example:
@@ -1687,7 +1685,7 @@ Normally Rails automatically generates the proper SQL to fetch the association m
h6(#has_and_belongs_to_many-foreign_key). +:foreign_key+
-By convention, Rails guesses that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
+By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
<ruby>
class User < ActiveRecord::Base
diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile
index 19378d63ce..721c791a33 100644
--- a/railties/guides/source/caching_with_rails.textile
+++ b/railties/guides/source/caching_with_rails.textile
@@ -188,7 +188,7 @@ end
You may notice that the actual product gets passed to the sweeper, so if we were caching the edit action for each product, we could add an expire method which specifies the page we want to expire:
<ruby>
- expire_action(:controller => 'products', :action => 'edit', :id => product)
+expire_action(:controller => 'products', :action => 'edit', :id => product.id)
</ruby>
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:
@@ -289,7 +289,11 @@ ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"
With this cache store, multiple server processes on the same host can share a cache. Servers processes running on different hosts could share a cache by using a shared file system, but that set up would not be ideal and is not recommended. The cache store is appropriate for low to medium traffic sites that are served off one or two hosts.
-Note that the cache will grow until the disk is full unless you periodically clear out old entries.
+Note that the cache will grow until the disk is full unless you periodically clear out old entries. You can call +ActiveSupport::Cache::FileStore#cleanup+ to remove entries older than a specified time.
+
+<ruby>
+Rails.cache.cleanup(:not_accessed_in => 2.days)
+</ruby>
h4. ActiveSupport::Cache::MemCacheStore
diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile
index f6b33d283c..3f8643eca3 100644
--- a/railties/guides/source/command_line.textile
+++ b/railties/guides/source/command_line.textile
@@ -381,15 +381,15 @@ $ rake about
About your application's environment
Ruby version 1.8.7 (x86_64-linux)
RubyGems version 1.3.6
-Rack version 1.1
-Rails version 3.1.0
+Rack version 1.3
+Rails version 3.2.0.beta
JavaScript Runtime Node.js (V8)
-Active Record version 3.1.0
-Action Pack version 3.1.0
-Active Resource version 3.1.0
-Action Mailer version 3.1.0
-Active Support version 3.1.0
-Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::MethodOverride, ActionDispatch::Head
+Active Record version 3.2.0.beta
+Action Pack version 3.2.0.beta
+Active Resource version 3.2.0.beta
+Action Mailer version 3.2.0.beta
+Active Support version 3.2.0.beta
+Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, ActionDispatch::Head, Rack::ConditionalGet, Rack::ETag, ActionDispatch::BestStandardsSupport
Application root /home/foobar/commandsapp
Environment development
Database adapter sqlite3
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index 41b53440f7..58b92e7f9e 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -64,7 +64,7 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is
* +config.autoload_paths+ accepts an array of paths from which Rails will autoload constants. Default is all directories under +app+.
-* +config.cache_classes+ controls whether or not application classes and modules should be reloaded on each request. Defaults to true in development mode, and false in test and production modes. Can also be enabled with +threadsafe!+.
+* +config.cache_classes+ controls whether or not application classes and modules should be reloaded on each request. Defaults to false in development mode, and true in test and production modes. Can also be enabled with +threadsafe!+.
* +config.action_view.cache_template_loading+ controls whether or not templates should be reloaded on each request. Defaults to whatever is set for +config.cache_classes+.
@@ -179,16 +179,16 @@ h4. Configuring Middleware
Every Rails application comes with a standard set of middleware which it uses in this order in the development environment:
-* +Rack::SSL+ Will force every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. Options passed to this can be configured by using +config.ssl_options+.
+* +Rack::SSL+ forces every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. Options passed to this can be configured by using +config.ssl_options+.
* +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is +true+.
-* +Rack::Lock+ Will wrap the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default.
-* +ActiveSupport::Cache::Strategy::LocalCache+ Serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread.
-* +Rack::Runtime+ Sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request.
-* +Rails::Rack::Logger+ Notifies the logs that the request has began. After request is complete, flushes all the logs.
-* +ActionDispatch::ShowExceptions+ Rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to +true+. If +config.action_dispatch.show_exceptions+ is set to +false+, exceptions will be raised regardless.
-* +ActionDispatch::RemoteIp+ Checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings.
-* +Rack::Sendfile+ Intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+.
-* +ActionDispatch::Callbacks+ Runs the prepare callbacks before serving the request.
+* +Rack::Lock+ wraps the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default.
+* +ActiveSupport::Cache::Strategy::LocalCache+ serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread.
+* +Rack::Runtime+ sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request.
+* +Rails::Rack::Logger+ notifies the logs that the request has began. After request is complete, flushes all the logs.
+* +ActionDispatch::ShowExceptions+ rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to +true+. If +config.action_dispatch.show_exceptions+ is set to +false+, exceptions will be raised regardless.
+* +ActionDispatch::RemoteIp+ checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings.
+* +Rack::Sendfile+ intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+.
+* +ActionDispatch::Callbacks+ runs the prepare callbacks before serving the request.
* +ActiveRecord::ConnectionAdapters::ConnectionManagement+ cleans active connections after each request, unless the +rack.test+ key in the request environment is set to +true+.
* +ActiveRecord::QueryCache+ caches all SELECT queries generated in a request. If any INSERT or UPDATE takes place then the cache is cleaned.
* +ActionDispatch::Cookies+ sets cookies for the request.
@@ -461,12 +461,31 @@ Rails has 5 initialization events which can be hooked into (listed in the order
* +before_initialize+: This is run directly before the initialization process of the application occurs with the +:bootstrap_hook+ initializer near the beginning of the Rails initialization process.
-* +to_prepare+: Run after the initializers are ran for all Railties (including the application itself), but before eager loading and the middleware stack is built.
+* +to_prepare+: Run after the initializers are ran for all Railties (including the application itself), but before eager loading and the middleware stack is built. More importantly, will run upon every request in +development+, but only once (during boot-up) in +production+ and +test+.
* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the _production_ environment and not for the +development+ environment.
* +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run.
+To define an event for these hooks, use the block syntax within a +Rails::Aplication+, +Rails::Railtie+ or +Rails::Engine+ subclass:
+
+<ruby>
+module YourApp
+ class Application < Rails::Application
+ config.before_initialize do
+ # initialization code goes here
+ end
+ end
+end
+</ruby>
+
+Alternatively, you can also do it through the +config+ method on the +Rails.application+ object:
+
+<ruby>
+Rails.application.config.before_initialize do
+ # initialization code goes here
+end
+</ruby>
WARNING: Some parts of your application, notably observers and routing, are not yet set up at the point where the +after_initialize+ block is called.
diff --git a/railties/guides/source/engines.textile b/railties/guides/source/engines.textile
new file mode 100644
index 0000000000..da56f3d0ed
--- /dev/null
+++ b/railties/guides/source/engines.textile
@@ -0,0 +1,606 @@
+h2. Getting Started with Engines
+
+In this guide you will learn about engines and how they can be used to provide additional functionality to their host applications through a clean and very easy-to-use interface. You will learn the following things in this guide:
+
+* What makes an engine
+* How to generate an engine
+* Building features for the engine
+* Hooking the engine into an application
+* Overriding engine functionality in the application
+
+endprologue.
+
+h3. What are engines?
+
+Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the +Rails::Application+ class inheriting from +Rails::Engine+. Therefore, engines and applications share common functionality but are at the same time two separate beasts. Engines and applications also share a common structure, as you'll see throughout this guide.
+
+Engines are also closely related to plugins where the two share a common +lib+ directory structure and are both generated using the +rails plugin new+ generator.
+
+The engine that will be generated for this guide will be called "blorgh". The engine will provide blogging functionality to its host applications, allowing for new posts and comments to be created. For now, you will be working solely within the engine itself and in later sections you'll see how to hook it into an application.
+
+Engines can also be isolated from their host applications. This means that an application is able to have a path provided by a routing helper such as +posts_path+ and use an engine also that provides a path also called +posts_path+, and the two would not clash. Along with this, controllers, models and table names are also namespaced. You'll see how to do this later in this guide.
+
+To see demonstrations of other engines, check out "Devise":https://github.com/plataformatec/devise, an engine that provides authentication for its parent applications, or "Forem":https://github.com/radar/forem, an engine that provides forum functionality.
+
+Finally, engines would not have be possible without the work of James Adam, Piotr Sarnacki, the Rails Core Team, and a number of other people. If you ever meet them, don't forget to say thanks!
+
+h3. Generating an engine
+
+To generate an engine with Rails 3.1, you will need to run the plugin generator and pass it the +--mountable+ option. To generate the beginnings of the "blorgh" engine you will need to run this command in a terminal:
+
+<shell>
+$ rails plugin new blorgh --mountable
+</shell>
+
+The +--mountable+ option tells the plugin generator that you want to create an engine (which is a mountable plugin, hence the option name), creating the basic directory structure of an engine by providing things such as the foundations of an +app+ folder, as well a +config/routes.rb+ file. This generator also provides a file at +lib/blorgh/engine.rb+ which is identical in function to an application's +config/application.rb+ file.
+
+h4. Inside an engine
+
+h5. Critical files
+
+At the root of the engine's directory, lives a +blorgh.gemspec+ file. When you include the engine into the application later on, you will do so with this line in a Rails application's +Gemfile+:
+
+<ruby>
+ gem 'blorgh', :path => "vendor/engines/blorgh"
+</ruby>
+
+By specifying it as a gem within the +Gemfile+, Bundler will load it as such, parsing this +blorgh.gemspec+ file and requiring a file within the +lib+ directory called +lib/blorgh.rb+. This file requires the +blorgh/engine.rb+ file (located at +lib/blorgh/engine.rb+) and defines a base module called +Blorgh+.
+
+<ruby>
+require "blorgh/engine"
+
+module Blorgh
+end
+</ruby>
+
+Within +lib/blorgh/engine.rb+ is the base class for the engine:
+
+<ruby>
+module Blorgh
+ class Engine < Rails::Engine
+ isolate_namespace Blorgh
+ end
+end
+</ruby>
+
+By inheriting from the +Rails::Engine+ class, this engine gains all the functionality it needs, such as being able to serve requests to its controllers.
+
+The +isolate_namespace+ method here deserves special notice. This call is responsible for isolating the controllers, models, routes and other things into their own namespace. Without this, there is a possibility that the engine's components could "leak" into the application, causing unwanted disruption. It is recommended that this line be left within this file.
+
+h5. +app+ directory
+
+Inside the +app+ directory there lives the standard +assets+, +controllers+, +helpers+, +mailers+, +models+ and +views+ directories that you should be familiar with from an application. The +helpers+, +mailers+ and +models+ directories are empty and so aren't described in this section. We'll look more into models in a future section.
+
+Within the +app/assets+ directory, there is the +images+, +javascripts+ and +stylesheets+ directories which, again, you should be familiar with due to their similarities of an application. One difference here however is that each directory contains a sub-directory with the engine name. Because this engine is going to be namespaced, its assets should be too.
+
+Within the +app/controllers+ directory there is a +blorgh+ directory and inside that a file called +application_controller.rb+. This file will provide any common functionality for the controllers of the engine. The +blorgh+ directory is where the other controllers for the engine will go. By placing them within this namespaced directory, you prevent them from possibly clashing with identically-named controllers within other engines or even within the application.
+
+Lastly, the +app/views+ directory contains a +layouts+ folder which contains file at +blorgh/application.html.erb+ which allows you to specify a layout for the engine. If this engine is to be used as a stand-alone engine, then you would add any customization to its layout in this file, rather than the applications +app/views/layouts/application.html.erb+ file.
+
+h5. +script+ directory
+
+This directory contains one file, +script/rails+, which allows you to use the +rails+ sub-commands and generators just like you would within an application. This means that you will very easily be able to generate new controllers and models for this engine.
+
+h5. +test+ directory
+
+The +test+ directory is where tests for the engine will go. To test the engine, there is a cut-down version of a Rails application embedded within it at +test/dummy+. This application will mount the engine in the +test/dummy/config/routes.rb+ file:
+
+<ruby>
+Rails.application.routes.draw do
+
+ mount Blorgh::Engine => "/blorgh"
+end
+</ruby>
+
+This line mounts the engine at the path of +/blorgh+, which will make it accessible through the application only at that path. We will look more into mounting an engine after some features have been developed.
+
+Also in the test directory is the +test/integration+ directory, where integration tests for the engine should be placed.
+
+h3. Providing engine functionality
+
+The engine that this guide covers will provide posting and commenting functionality and follows a similar thread to the "Getting Started Guide":getting-started.html, with some new twists.
+
+h4. Generating a post resource
+
+The first thing to generate for a blog engine is the +Post+ model and related controller. To quickly generate this, you can use the Rails scaffold generator.
+
+<shell>
+$ rails generate scaffold post title:string text:text
+</shell>
+
+This command will output this information:
+
+<shell>
+invoke active_record
+create db/migrate/[timestamp]_create_blorgh_posts.rb
+create app/models/blorgh/post.rb
+invoke test_unit
+create test/unit/blorgh/post_test.rb
+create test/fixtures/blorgh/posts.yml
+ route resources :posts
+invoke scaffold_controller
+create app/controllers/blorgh/posts_controller.rb
+invoke erb
+create app/views/blorgh/posts
+create app/views/blorgh/posts/index.html.erb
+create app/views/blorgh/posts/edit.html.erb
+create app/views/blorgh/posts/show.html.erb
+create app/views/blorgh/posts/new.html.erb
+create app/views/blorgh/posts/_form.html.erb
+invoke test_unit
+create test/functional/blorgh/posts_controller_test.rb
+invoke helper
+create app/helpers/blorgh/posts_helper.rb
+invoke test_unit
+create test/unit/helpers/blorgh/posts_helper_test.rb
+invoke assets
+invoke js
+create app/assets/javascripts/blorgh/posts.js
+invoke css
+create app/assets/stylesheets/blorgh/posts.css
+invoke css
+create app/assets/stylesheets/scaffold.css
+</shell>
+
+The first thing that the scaffold generator does is invoke the +active_record+ generator, which generates a migration and a model for the resource. Note here, however, that the migration is called +create_blorgh_posts+ rather than the usual +create_posts+. This is due to the +isolate_namespace+ method called in the +Blorgh::Engine+ class's definition. The model here is also namespaced, being placed at +app/models/blorgh/post.rb+ rather than +app/models/post.rb+.
+
+Next, the +test_unit+ generator is invoked for this model, generating a unit test at +test/unit/blorgh/post_test.rb+ (rather than +test/unit/post_test.rb+) and a fixture at +test/fixtures/blorgh/posts.yml+ (rather than +test/fixtures/posts.yml+).
+
+After that, a line for the resource is inserted into the +config/routes.rb+ file for the engine. This line is simply +resources :posts+, turning the +config/routes.rb+ file into this:
+
+<ruby>
+Blorgh::Engine.routes.draw do
+ resources :posts
+
+end
+</ruby>
+
+Note here that the routes are drawn upon the +Blorgh::Engine+ object rather than the +YourApp::Application+ class. This is so that the engine routes are confined to the engine itself and can be mounted at a specific point as shown in the "test directory":#test-directory section.
+
+Next, the +scaffold_controller+ generator is invoked, generating a controlled called +Blorgh::PostsController+ (at +app/controllers/blorgh/posts_controller.rb+) and its related views at +app/views/blorgh/posts+. This generator also generates a functional test for the controller (+test/functional/blorgh/posts_controller_test.rb+) and a helper (+app/helpers/blorgh/posts_controller.rb+).
+
+Everything this generator has generated is neatly namespaced. The controller's class is defined within the +Blorgh+ module:
+
+<ruby>
+module Blorgh
+ class PostsController < ApplicationController
+ ...
+ end
+end
+</ruby>
+
+NOTE: The +ApplicationController+ class being inherited from here is the +Blorgh::ApplicationController+, not an application's +ApplicationController+.
+
+The helper is also namespaced:
+
+<ruby>
+module Blorgh
+ class PostsHelper
+ ...
+ end
+end
+</ruby>
+
+This helps prevent conflicts with any other engine or application that may have a post resource also.
+
+Finally, two files that are the assets for this resource are generated, +app/assets/javascripts/blorgh/posts.js+ and +app/assets/javascripts/blorgh/posts.css+. You'll see how to use these a little later.
+
+By default, the scaffold styling is not applied to the engine as the engine's layout file, +app/views/blorgh/application.html.erb+ doesn't load it. To make this apply, insert this line into the +<head>+ tag of this layout:
+
+<erb>
+<%= stylesheet_link_tag "scaffold" %>
+</erb>
+
+You can see what the engine has so far by running +rake db:migrate+ at the root of our engine to run the migration generated by the scaffold generator, and then running +rails server+. When you open +http://localhost:3000/blorgh/posts+ you will see the default scaffold that has been generated.
+
+!images/engines_scaffold.png(Blank engine scaffold)!
+
+Click around! You've just generated your first engine's first functions.
+
+If you'd rather play around in the console, +rails console+ will also work just like a Rails application. Remember: the +Post+ model is namespaced, so to reference it you must call it as +Blorgh::Post+.
+
+<ruby>
+ >> Blorgh::Post.find(1)
+ => #<Blorgh::Post id: 1 ...>
+</ruby>
+
+One final thing is that the +posts+ resource for this engine should be the root of the engine. Whenever someone goes to the root path where the engine is mounted, they should be shown a list of posts. This can be made to happen if this line is inserted into the +config/routes.rb+ file inside the engine:
+
+<ruby>
+root :to => "posts#index"
+</ruby>
+
+Now people will only need to go to the root of the engine to see all the posts, rather than visiting +/posts+.
+
+h4. Generating a comments resource
+
+Now that the engine has the ability to create new blog posts, it only makes sense to add commenting functionality as well. To do get this, you'll need to generate a comment model, a comment controller and then modify the posts scaffold to display comments and allow people to create new ones.
+
+Run the model generator and tell it to generate a +Comment+ model, with the related table having two columns: a +post_id+ integer and +text+ text column.
+
+<shell>
+$ rails generate model Comment post_id:integer text:text
+</shell>
+
+This will output the following:
+
+<shell>
+invoke active_record
+create db/migrate/[timestamp]_create_blorgh_comments.rb
+create app/models/blorgh/comment.rb
+invoke test_unit
+create test/unit/blorgh/comment_test.rb
+create test/fixtures/blorgh/comments.yml
+</shell>
+
+This generator call will generate just the necessary model files it needs, namespacing the files under a +blorgh+ directory and creating a model class called +Blorgh::Comment+.
+
+To show the comments on a post, edit +app/views/posts/show.html.erb+ and add this line before the "Edit" link:
+
+<erb>
+<h3>Comments</h3>
+<%= render @post.comments %>
+</erb>
+
+This line will require there to be a +has_many+ association for comments defined on the +Blorgh::Post+ model, which there isn't right now. To define one, open +app/models/blorgh/post.rb+ and add this line into the model:
+
+<ruby>
+has_many :comments
+</ruby>
+
+Turning the model into this:
+
+<ruby>
+module Blorgh
+ class Post < ActiveRecord::Base
+ has_many :comments
+ end
+end
+</ruby>
+
+Because the +has_many+ is defined inside a class that is inside the +Blorgh+ module, Rails will know that you want to use the +Blorgh::Comment+ model for these objects.
+
+Next, there needs to be a form so that comments can be created on a post. To add this, put this line underneath the call to +render @post.comments+ in +app/views/blorgh/posts/show.html.erb+:
+
+<erb>
+<%= render "blorgh/comments/form" %>
+</erb>
+
+Next, the partial that this line will render needs to exist. Create a new directory at +app/views/blorgh/comments+ and in it a new file called +_form.html.erb+ which has this content to create the required partial:
+
+<erb>
+<h3>New comment</h3>
+<%= form_for [@post, @post.comments.build] do |f| %>
+ <p>
+ <%= f.label :text %><br />
+ <%= f.text_area :text %>
+ </p>
+ <%= f.submit %>
+<% end %>
+</erb>
+
+This form, when submitted, is going to attempt to post to a route of +posts/:post_id/comments+ within the engine. This route doesn't exist at the moment, but can be created by changing the +resources :posts+ line inside +config/routes.rb+ into these lines:
+
+<ruby>
+resources :posts do
+ resources :comments
+end
+</ruby>
+
+The route now will exist, but the controller that this route goes to does not. To create it, run this command:
+
+<shell>
+$ rails g controller comments
+</shell>
+
+This will generate the following things:
+
+<shell>
+create app/controllers/blorgh/comments_controller.rb
+invoke erb
+ exist app/views/blorgh/comments
+invoke test_unit
+create test/functional/blorgh/comments_controller_test.rb
+invoke helper
+create app/helpers/blorgh/comments_helper.rb
+invoke test_unit
+create test/unit/helpers/blorgh/comments_helper_test.rb
+invoke assets
+invoke js
+create app/assets/javascripts/blorgh/comments.js
+invoke css
+create app/assets/stylesheets/blorgh/comments.css
+</shell>
+
+The form will be making a +POST+ request to +/posts/:post_id/comments+, which will correspond with the +create+ action in +Blorgh::CommentsController+. This action needs to be created and can be done by putting the following lines inside the class definition in +app/controllers/blorgh/comments_controller.rb+:
+
+<ruby>
+def create
+ @post = Post.find(params[:post_id])
+ @comment = @post.comments.build(params[:comment])
+ flash[:notice] = "Comment has been created!"
+ redirect_to post_path
+end
+</ruby>
+
+This is the final part required to get the new comment form working. Displaying the comments however, is not quite right yet. If you were to create a comment right now you would see this error:
+
+<text>
+ Missing partial blorgh/comments/comment with {:handlers=>[:erb, :builder], :formats=>[:html], :locale=>[:en, :en]}. Searched in:
+ * "/Users/ryan/Sites/side_projects/blorgh/test/dummy/app/views"
+ * "/Users/ryan/Sites/side_projects/blorgh/app/views"
+</text>
+
+The engine is unable to find the partial required for rendering the comments. Rails has looked firstly in the application's (+test/dummy+) +app/views+ directory and then in the engine's +app/views+ directory. When it can't find it, it will throw this error. The engine knows to look for +blorgh/comments/comment+ because the model object it is receiving is from the +Blorgh::Comment+ class.
+
+This partial will be responsible for rendering just the comment text, for now. Create a new file at +app/views/blorgh/comments/_comment.html.erb+ and put this line inside it:
+
+<erb>
+<%= comment_counter + 1 %>. <%= comment.text %>
+</erb>
+
+The +comment_counter+ local variable is given to us by the +<%= render @post.comments %>+ call, as it will define this automatically and increment the counter as it iterates through each comment. It's used in this example to display a small number next to each comment when it's created.
+
+That completes the comment function of the blogging engine. Now it's time to use it within an application.
+
+h3. Hooking into an application
+
+Using an engine within an application is very easy. This section covers how to mount the engine into an application and the initial setup required for it, as well as linking the engine to a +User+ class provided by the application to provide ownership for posts and comments within the engine.
+
+h4. Mounting the engine
+
+First, the engine needs to be specified inside the application's +Gemfile+. If there isn't an application handy to test this out in, generate one using the +rails new+ command outside of the engine directory like this:
+
+<shell>
+$ rails new unicorn
+</shell>
+
+Usually, specifying the engine inside the Gemfile would be done by specifying it as a normal, everyday gem.
+
+<ruby>
+gem 'devise'
+</ruby>
+
+Because the +blorgh+ engine is still under development, it will need to have a +:path+ option for its +Gemfile+ specification:
+
+<ruby>
+gem 'blorgh', :path => "/path/to/blorgh"
+</ruby>
+
+If the whole +blorgh+ engine directory is copied to +vendor/engines/blorgh+ then it could be specified in the +Gemfile+ like this:
+
+<ruby>
+gem 'blorgh', :path => "vendor/engines/blorgh"
+</ruby>
+
+As described earlier, by placing the gem in the +Gemfile+ it will be loaded when Rails is loaded, as it will first require +lib/blorgh.rb+ in the engine and then +lib/blorgh/engine.rb+, which is the file that defines the major pieces of functionality for the engine.
+
+To make the engine's functionality accessible from within an application, it needs to be mounted in that application's +config/routes.rb+ file:
+
+<ruby>
+mount Blorgh::Engine, :at => "blog"
+</ruby>
+
+This line will mount the engine at +blog+ in the application. Making it accessible at +http://localhost:3000/blog+ when the application runs with +rails s+.
+
+NOTE: Other engines, such as Devise, handle this a little differently by making you specify custom helpers such as +devise_for+ in the routes. These helpers do exactly the same thing, mounting pieces of the engines's functionality at a pre-defined path which may be customizable.
+
+h4. Engine setup
+
+The engine contains migrations for the +blorgh_posts+ and +blorgh_comments+ table which need to be created in the application's database so that the engine's models can query them correctly. To copy these migrations into the application use this command:
+
+<shell>
+$ rake blorgh:install:migrations
+</shell>
+
+This command, when run for the first time will copy over all the migrations from the engine. When run the next time, it will only copy over migrations that haven't been copied over already. The first run for this command will output something such as this:
+
+<shell>
+Copied migration [timestamp_1]_create_blorgh_posts.rb from blorgh
+Copied migration [timestamp_2]_create_blorgh_comments.rb from blorgh
+</shell>
+
+The first timestamp (+\[timestamp_1\]+) will be the current time and the second timestamp (+\[timestamp_2\]+) will be the current time plus a second. The reason for this is so that the migrations for the engine are run after any existing migrations in the application.
+
+To run these migrations within the context of the application, simply run +rake db:migrate+. When accessing the engine through +http://localhost:3000/blog+, the posts will be empty. This is because the table created inside the application is different from the one created within the engine. Go ahead, play around with the newly mounted engine. You'll find that it's the same as when it was only an engine.
+
+h4. Using a class provided by the application
+
+When an engine is created, it may want to use specific classes from an application to provide links between the pieces of the engine and the pieces of the application. In the case of the +blorgh+ engine, making posts and comments have authors would make a lot of sense.
+
+Usually, an application would have a +User+ class that would provide the objects that would represent the posts' and comments' authors, but there could be a case where the application calls this class something different, such as +Person+. It's because of this reason that the engine should not hardcode the associations to be exactly for a +User+ class, but should allow for some flexibility around what the class is called.
+
+To keep it simple in this case, the application will have a class called +User+ which will represent the users of the application. It can be generated using this command:
+
+<shell>
+rails g model user name:string
+</shell>
+
+The +rake db:migrate+ command needs to be run here to ensure that our application has the +users+ table for future use.
+
+Also to keep it simple, the posts form will have a new text field called +author_name_+ where users can elect to put their name. The engine will then take this name and create a new +User+ object from it or find one that already has that name, and then associate the post with it.
+
+First, the +author_name+ text field needs to be added to the +app/views/blorgh/posts/_form.html.erb+ partial inside the engine. This can be added above the +title+ field with this code:
+
+<erb>
+<div class="field">
+ <%= f.label :author_name %><br />
+ <%= f.text_field :author_name %>
+</div>
+</erb>
+
+The +Blorgh::Post+ model should then have some code to convert the +author_name+ field into an actual +User+ object and associate it as that post's +author+ before the post is saved. It will also need to have an +attr_accessor+ setup for this field so that the setter and getter methods are defined for it.
+
+To do all this, you'll need to add the +attr_accessor+ for +author_name+, the association for the author and the +before_save+ call into +app/models/blorgh/post.rb+. The +author+ association will be hard-coded to the +User+ class for the time being.
+
+<ruby>
+attr_accessor :author_name
+belongs_to :author, :class_name => "User"
+
+before_save :set_author
+
+private
+ def set_author
+ self.author = User.find_or_create_by_name(author_name)
+ end
+</ruby>
+
+By defining that the +author+ association's object is represented by the +User+ class a link is established between the engine and the application. There needs to be a way of associating the records in the +blorgh_posts+ table with the records in the +users+ table. Because the association is called +author+, there should be an +author_id+ column added to the +blorgh_posts+ table.
+
+To generate this new column, run this command within the engine:
+
+<shell>
+$ rails g migration add_author_id_to_blorgh_posts author_id:integer
+</shell>
+
+NOTE: Due to the migration's name and the column specification after it, Rails will automatically know that you want to add a column to a specific table and write that into the migration for you. You don't need to tell it any more than this.
+
+This migration will need to be run on the application. To do that, it must first be copied using this command:
+
+<shell>
+$ rake blorgh:install:migrations
+</shell>
+
+Notice here that only _one_ migration was copied over here. This is because the first two migrations were copied over the first time this command was run.
+
+<shell>
+ NOTE: Migration [timestamp]_create_blorgh_posts.rb from blorgh has been skipped. Migration with the same name already exists.
+ NOTE: Migration [timestamp]_create_blorgh_comments.rb from blorgh has been skipped. Migration with the same name already exists.
+ Copied migration [timestamp]_add_author_id_to_blorgh_posts.rb from blorgh
+</shell>
+
+Run this migration using this command:
+
+<shell>
+$ rake db:migrate
+</shell>
+
+Now with all the pieces in place, an action will take place that will associate an author -- represented by a record in the +users+ table -- with a post, represented by the +blorgh_posts+ table from the engine.
+
+Finally, the author's name should be displayed on the post's page. Add this code above the "Title" output inside +app/views/blorgh/posts/show.html.erb+:
+
+<erb>
+<p>
+ <b>Author:</b>
+ <%= @post.author %>
+</p>
+</erb>
+
+WARNING: For posts created previously, this will break the +show+ page for them. We recommend deleting these posts and starting again, or manually assigning an author using +rails c+.
+
+By outputting +@post.author+ using the +<%=+ tag the +to_s+ method will be called on the object. By default, this will look quite ugly:
+
+<text>
+#<User:0x00000100ccb3b0>
+</text>
+
+This is undesirable and it would be much better to have the user's name there. To do this, add a +to_s+ method to the +User+ class within the application:
+
+<ruby>
+def to_s
+ name
+end
+</ruby>
+
+Now instead of the ugly Ruby object output the author's name will be displayed.
+
+h4. Configuring an engine
+
+The next step is to make the class that represents a +User+ in the application customizable for the engine. This is because, as explained before, that class may not always be +User+. To make this customizable, the engine will have a configuration setting called +user_class+ that will be used to specify what the class representing users is inside the application.
+
+To define this configuration setting, you should use a +mattr_accessor+ inside the +Blorgh+ module for the engine, located at +lib/blorgh.rb+ inside the engine. Inside this module, put this line:
+
+<ruby>
+mattr_accessor :user_class
+</ruby>
+
+This method works like its brothers +attr_accessor+ and +cattr_accessor+, but provides a setter and getter method on the module with the specified name. To use it, it must be referenced using +Blorgh.user_class+.
+
+The next step is switching the +Blorgh::Post+ model over to this new setting. For the +belongs_to+ association inside this model (+app/models/blorgh/post.rb+), it will now become this:
+
+<ruby>
+belongs_to :author, :class_name => Blorgh.user_class
+</ruby>
+
+The +set_author+ method also located in this class should also use this class:
+
+<ruby>
+self.author = Blorgh.user_class.constantize.find_or_create_by_name(author_name)
+</ruby>
+
+To set this configuration setting within the application, an initializer should be used. By using an initializer, the configuration will be set up before the application starts and makes references to the classes of the engine which may depend on this configuration setting existing.
+
+Create a new initializer at +config/initializers/blorgh.rb+ inside the application where the +blorgh+ engine is installed and put this content in it:
+
+<ruby>
+Blorgh.user_class = "User"
+</ruby>
+
+WARNING: It's very important here to use the +String+ version of the class, rather than the class itself. If you were to use the class, Rails would attempt to load that class and then reference the related table, which could lead to problems if the table wasn't already existing. Therefore, a +String+ should be used and then converted to a class using +constantize+ in the engine later on.
+
+Go ahead and try to create a new post. You will see that it works exactly in the same way as before, except this time the engine is using the configuration setting in +config/initializers/blorgh.rb+ to learn what the class is.
+
+There are now no strict dependencies on what the class is, only what the class's API must be. The engine simply requires this class to define a +find_or_create_by_name+ method which returns an object of that class to be associated with a post when it's created.
+
+h3. Extending engine functionality
+
+This section looks at overriding or adding functionality to the views, controllers and models provided by an engine.
+
+h4. Overriding views
+
+When Rails looks for a view to render, it will first look in the +app/views+ directory of the application. If it cannot find the view there, then it will check in the +app/views+ directories of all engines which have this directory.
+
+In the +blorgh+ engine, there is a currently a file at +app/views/blorgh/posts/index.html.erb+. When the engine is asked to render the view for +Blorgh::PostsController+'s +index+ action, it will first see if it can find it at +app/views/blorgh/posts/index.html.erb+ within the application and then if it cannot it will look inside the engine.
+
+By overriding this view in the application, by simply creating a new file at +app/views/blorgh/posts/index.html.erb+, you can completely change what this view would normally output.
+
+Try this now by creating a new file at +app/views/blorgh/posts/index.html.erb+ and put this content in it:
+
+<erb>
+<h1>Posts</h1>
+<%= link_to "New Post", new_post_path %>
+<% @posts.each do |post| %>
+ <h2><%= post.title %></h2>
+ <small>By <%= post.author %></small>
+ <%= simple_format(post.text) %>
+ <hr>
+<% end %>
+</erb>
+
+Rather than looking like the default scaffold, the page will now look like this:
+
+!images/engines_post_override.png(Engine scaffold overriden)!
+
+h4. Controllers
+
+TODO: Explain how to extend a controller.
+IDEA: I like Devise's +devise :controllers => { "sessions" => "sessions" }+ idea. Perhaps we could incorporate that into the guide?
+
+h4. Models
+
+TODO: Explain how to extend models provided by an engine.
+
+h4. Routes
+
+Within the application, you may wish to link to some area within the engine. Due to the fact that the engine's routes are isolated (by the +isolate_namespace+ call within the +lib/blorgh/engine.rb+ file), you will need to prefix these routes with the engine name. This means rather than having something such as:
+
+<erb>
+<%= link_to "Blog posts", posts_path %>
+</erb>
+
+It needs to be written as:
+
+<erb>
+<%= link_to "Blog posts", blorgh.posts_path %>
+</erb>
+
+This allows for the engine _and_ the application to both have a +posts_path+ routing helper and to not interfere with each other. You may also reference another engine's routes from inside an engine using this same syntax.
+
+If you wish to reference the application inside the engine in a similar way, use the +main_app+ helper:
+
+<erb>
+<%= link_to "Home", main_app.root_path %>
+</erb>
+
+TODO: Mention how to use assets within an engine?
+TODO: Mention how to depend on external gems, like RedCarpet.
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index 33f383f173..bf6104b96b 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -360,7 +360,7 @@ development:
h5. Configuring an SQLite3 Database for JRuby Platform
-If you choose to use SQLite3 and using JRuby, your +config/database.yml+ will
+If you choose to use SQLite3 and are using JRuby, your +config/database.yml+ will
look a little different. Here's the development section:
<yaml>
@@ -371,7 +371,7 @@ development:
h5. Configuring a MySQL Database for JRuby Platform
-If you choose to use MySQL and using JRuby, your +config/database.yml+ will look
+If you choose to use MySQL and are using JRuby, your +config/database.yml+ will look
a little different. Here's the development section:
<yaml>
@@ -384,7 +384,7 @@ development:
h5. Configuring a PostgreSQL Database for JRuby Platform
-Finally if you choose to use PostgreSQL and using JRuby, your
+Finally if you choose to use PostgreSQL and are using JRuby, your
+config/database.yml+ will look a little different. Here's the development
section:
@@ -599,7 +599,7 @@ The above migration creates a method named +change+ which will be called when yo
run this migration. The action defined in that method is also reversible, which
means Rails knows how to reverse the change made by this migration, in case you
want to reverse it at later date. By default, when you run this migration it
-will creates a +posts+ table with two string columns and a text column. It also
+creates a +posts+ table with two string columns and a text column. It also
creates two timestamp fields to track record creation and updating. More
information about Rails migrations can be found in the "Rails Database
Migrations":migrations.html guide.
@@ -620,9 +620,9 @@ table.
== CreatePosts: migrated (0.0020s) ===========================================
</shell>
-NOTE. Because you're working in the development environment by default, this
+NOTE. Because by default you're working in the development environment, this
command will apply to the database defined in the +development+ section of your
-+config/database.yml+ file. If you would like to execute migrations in other
++config/database.yml+ file. If you would like to execute migrations in another
environment, for instance in production, you must explicitly pass it when
invoking the command: <tt>rake db:migrate RAILS_ENV=production</tt>.
@@ -704,8 +704,8 @@ $ rails console
</shell>
TIP: The default console will make changes to your database. You can instead
-open a console that will roll back any changes you make by using +rails console
---sandbox+.
+open a console that will roll back any changes you make by using <tt>rails console
+--sandbox</tt>.
After the console loads, you can use it to work with your application's models:
@@ -783,7 +783,8 @@ Here's +app/views/posts/index.html.erb+:
<td><%= post.content %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
- <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
+ <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?',
+ :method => :delete %></td>
</tr>
<% end %>
</table>
@@ -867,10 +868,10 @@ The +new.html.erb+ view displays this empty Post to the user:
The +&lt;%= render 'form' %&gt;+ line is our first introduction to _partials_ in
Rails. A partial is a snippet of HTML and Ruby code that can be reused in
-multiple locations. In this case, the form used to make a new post, is basically
-identical to a form used to edit a post, both have text fields for the name and
-title and a text area for the content with a button to make a new post or update
-the existing post.
+multiple locations. In this case, the form used to make a new post is basically
+identical to the form used to edit a post, both having text fields for the name and
+title, a text area for the content, and a button to create the new post or to update
+the existing one.
If you take a look at +views/posts/_form.html.erb+ file, you will see the
following:
@@ -879,7 +880,8 @@ following:
<%= form_for(@post) do |f| %>
<% if @post.errors.any? %>
<div id="errorExplanation">
- <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
+ <h2><%= pluralize(@post.errors.count, "error") %> prohibited
+ this post from being saved:</h2>
<ul>
<% @post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
@@ -907,15 +909,15 @@ following:
</erb>
This partial receives all the instance variables defined in the calling view
-file, so in this case, the controller assigned the new Post object to +@post+
-and so, this is available in both the view and partial as +@post+.
+file. In this case, the controller assigned the new +Post+ object to +@post+,
+which will thus be available in both the view and the partial as +@post+.
For more information on partials, refer to the "Layouts and Rendering in
Rails":layouts_and_rendering.html#using-partials guide.
The +form_for+ block is used to create an HTML form. Within this block, you have
access to methods to build various controls on the form. For example,
-+f.text_field :name+ tells Rails to create a text input on the form, and to hook
++f.text_field :name+ tells Rails to create a text input on the form and to hook
it up to the +name+ attribute of the instance being displayed. You can only use
these methods with attributes of the model that the form is based on (in this
case +name+, +title+, and +content+). Rails uses +form_for+ in preference to
@@ -931,9 +933,9 @@ to a model, you should use the +form_tag+ method, which provides shortcuts for
building forms that are not necessarily tied to a model instance.
When the user clicks the +Create Post+ button on this form, the browser will
-send information back to the +create+ method of the controller (Rails knows to
-call the +create+ method because the form is sent with an HTTP POST request;
-that's one of the conventions that I mentioned earlier):
+send information back to the +create+ action of the controller (Rails knows to
+call the +create+ action because the form is sent with an HTTP POST request;
+that's one of the conventions that were mentioned earlier):
<ruby>
def create
@@ -965,12 +967,12 @@ If the post was not successfully saved, due to a validation error, then the
controller returns the user back to the +new+ action with any error messages so
that the user has the chance to fix the error and try again.
-The "Post was successfully created." message is stored inside of the Rails
-+flash+ hash, (usually just called _the flash_) so that messages can be carried
+The "Post was successfully created." message is stored in the Rails
++flash+ hash (usually just called _the flash_), so that messages can be carried
over to another action, providing the user with useful information on the status
of their request. In the case of +create+, the user never actually sees any page
-rendered during the Post creation process, because it immediately redirects to
-the new Post as soon Rails saves the record. The Flash carries over a message to
+rendered during the post creation process, because it immediately redirects to
+the new +Post+ as soon as Rails saves the record. The Flash carries over a message to
the next action, so that when the user is redirected back to the +show+ action,
they are presented with a message saying "Post was successfully created."
@@ -1043,9 +1045,9 @@ it:
<%= link_to 'Back', posts_path %>
</erb>
-Again, as with the +new+ action, the +edit+ action is using the +form+ partial,
-this time however, the form will do a PUT action to the PostsController and the
-submit button will display "Update Post"
+Again, as with the +new+ action, the +edit+ action is using the +form+ partial.
+This time, however, the form will do a PUT action to the +PostsController+ and the
+submit button will display "Update Post".
Submitting the form created by this view will invoke the +update+ action within
the controller:
@@ -1070,9 +1072,9 @@ end
In the +update+ action, Rails first uses the +:id+ parameter passed back from
the edit view to locate the database record that's being edited. The
-+update_attributes+ call then takes the rest of the parameters from the request
-and applies them to this record. If all goes well, the user is redirected to the
-post's +show+ view. If there are any problems, it's back to the +edit+ view to
++update_attributes+ call then takes the +post+ parameter (a hash) from the request
+and applies it to this record. If all goes well, the user is redirected to the
+post's +show+ action. If there are any problems, it redirects back to the +edit+ action to
correct them.
h4. Destroying a Post
@@ -1094,8 +1096,8 @@ end
The +destroy+ method of an Active Record model instance removes the
corresponding record from the database. After that's done, there isn't any
-record to display, so Rails redirects the user's browser to the index view for
-the model.
+record to display, so Rails redirects the user's browser to the index action of
+the controller.
h3. Adding a Second Model
@@ -1107,7 +1109,7 @@ h4. Generating a Model
Models in Rails use a singular name, and their corresponding database tables use
a plural name. For the model to hold comments, the convention is to use the name
-Comment. Even if you don't want to use the entire apparatus set up by
++Comment+. Even if you don't want to use the entire apparatus set up by
scaffolding, most Rails developers still use generators to make things like
models and controllers. To create the new model, run this command in your
terminal:
@@ -1118,8 +1120,8 @@ $ rails generate model Comment commenter:string body:text post:references
This command will generate four files:
-* +app/models/comment.rb+ - The model
-* +db/migrate/20100207235629_create_comments.rb+ - The migration
+* +app/models/comment.rb+ - The model.
+* +db/migrate/20100207235629_create_comments.rb+ - The migration.
* +test/unit/comment_test.rb+ and +test/fixtures/comments.yml+ - The test harness.
First, take a look at +comment.rb+:
@@ -1177,8 +1179,8 @@ Active Record associations let you easily declare the relationship between two
models. In the case of comments and posts, you could write out the relationships
this way:
-* Each comment belongs to one post
-* One post can have many comments
+* Each comment belongs to one post.
+* One post can have many comments.
In fact, this is very close to the syntax that Rails uses to declare this
association. You've already seen the line of code inside the Comment model that
@@ -1204,7 +1206,7 @@ end
These two declarations enable a good bit of automatic behavior. For example, if
you have an instance variable +@post+ containing a post, you can retrieve all
-the comments belonging to that post as the array +@post.comments+.
+the comments belonging to that post as an array using +@post.comments+.
TIP: For more information on Active Record associations, see the "Active Record
Associations":association_basics.html guide.
@@ -1213,9 +1215,9 @@ h4. Adding a Route for Comments
As with the +home+ controller, we will need to add a route so that Rails knows
where we would like to navigate to see +comments+. Open up the
-+config/routes.rb+ file again, you will see an entry that was added
-automatically for +posts+ near the top by the scaffold generator, +resources
-:posts+, edit it as follows:
++config/routes.rb+ file again. Near the top, you will see the entry for +posts+
+that was added automatically by the scaffold generator: <tt>resources
+:posts</tt>. Edit it as follows:
<ruby>
resources :posts do
@@ -1241,19 +1243,19 @@ $ rails generate controller Comments
This creates six files and one empty directory:
-* +app/controllers/comments_controller.rb+ - The controller
-* +app/helpers/comments_helper.rb+ - A view helper file
-* +test/functional/comments_controller_test.rb+ - The functional tests for the controller
-* +test/unit/helpers/comments_helper_test.rb+ - The unit tests for the helper
-* +app/views/comments/+ - Views of the controller are stored here
-* +app/assets/stylesheets/comment.css.scss+ - Cascading style sheet for the controller
-* +app/assets/javascripts/comment.js.coffee+ - CoffeeScript for the controller
+* +app/controllers/comments_controller.rb+ - The controller.
+* +app/helpers/comments_helper.rb+ - A view helper file.
+* +test/functional/comments_controller_test.rb+ - The functional tests for the controller.
+* +test/unit/helpers/comments_helper_test.rb+ - The unit tests for the helper.
+* +app/views/comments/+ - Views of the controller are stored here.
+* +app/assets/stylesheets/comment.css.scss+ - Cascading style sheet for the controller.
+* +app/assets/javascripts/comment.js.coffee+ - CoffeeScript for the controller.
Like with any blog, our readers will create their comments directly after
reading the post, and once they have added their comment, will be sent back to
the post show page to see their comment now listed. Due to this, our
+CommentsController+ is there to provide a method to create comments and delete
-SPAM comments when they arrive.
+spam comments when they arrive.
So first, we'll wire up the Post show template
(+/app/views/posts/show.html.erb+) to let us make a new comment:
@@ -1295,8 +1297,8 @@ So first, we'll wire up the Post show template
<%= link_to 'Back to Posts', posts_path %> |
</erb>
-This adds a form on the Post show page that creates a new comment, which will
-call the +CommentsController+ +create+ action, so let's wire that up:
+This adds a form on the +Post+ show page that creates a new comment by
+calling the +CommentsController+ +create+ action. Let's wire that up:
<ruby>
class CommentsController < ApplicationController
@@ -1309,9 +1311,9 @@ end
</ruby>
You'll see a bit more complexity here than you did in the controller for posts.
-That's a side-effect of the nesting that you've set up; each request for a
+That's a side-effect of the nesting that you've set up. Each request for a
comment has to keep track of the post to which the comment is attached, thus the
-initial find action to the Post model to get the post in question.
+initial call to the +find+ method of the +Post+ model to get the post in question.
In addition, the code takes advantage of some of the methods available for an
association. We use the +create+ method on +@post.comments+ to create and save
@@ -1381,9 +1383,9 @@ right places.
h3. Refactoring
-Now that we have Posts and Comments working, if we take a look at the
-+app/views/posts/show.html.erb+ template, it's getting long and awkward. We can
-use partials to clean this up.
+Now that we have posts and comments working, take a look at the
++app/views/posts/show.html.erb+ template. It is getting long and awkward. We can
+use partials to clean it up.
h4. Rendering Partial Collections
@@ -1403,7 +1405,7 @@ following into it:
</p>
</erb>
-Then in the +app/views/posts/show.html.erb+ you can change it to look like the
+Then you can change +app/views/posts/show.html.erb+ to look like the
following:
<erb>
@@ -1456,8 +1458,8 @@ comment to a local variable named the same as the partial, in this case
h4. Rendering a Partial Form
-Let's also move that new comment section out to its own partial. Again, you
-create a file +app/views/comments/_form.html.erb+ and in it you put:
+Let us also move that new comment section out to its own partial. Again, you
+create a file +app/views/comments/_form.html.erb+ containing:
<erb>
<%= form_for([@post, @post.comments.build]) do |f| %>
@@ -1508,7 +1510,7 @@ Then you make the +app/views/posts/show.html.erb+ look like the following:
</erb>
The second render just defines the partial template we want to render,
-<tt>comments/form</tt>, Rails is smart enough to spot the forward slash in that
+<tt>comments/form</tt>. Rails is smart enough to spot the forward slash in that
string and realize that you want to render the <tt>_form.html.erb</tt> file in
the <tt>app/views/comments</tt> directory.
@@ -1517,7 +1519,7 @@ defined it as an instance variable.
h3. Deleting Comments
-Another important feature on a blog is being able to delete SPAM comments. To do
+Another important feature of a blog is being able to delete spam comments. To do
this, we need to implement a link of some sort in the view and a +DELETE+ action
in the +CommentsController+.
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index 32b41fdd2c..f88405a2fd 100644
--- a/railties/guides/source/initialization.textile
+++ b/railties/guides/source/initialization.textile
@@ -7,7 +7,7 @@ This guide explains the internals of the initialization process in Rails as of R
endprologue.
-This guide goes through every single file, class and method call that is required to boot up the Ruby on Rails stack for a default Rails 3.1 application, explaining each part in detail a long the way. For this guide, we will be focusing on how the two most common methods (+rails server+ and Passenger) boot a Rails application.
+This guide goes through every single file, class and method call that is required to boot up the Ruby on Rails stack for a default Rails 3.1 application, explaining each part in detail along the way. For this guide, we will be focusing on how the two most common methods (+rails server+ and Passenger) boot a Rails application.
NOTE: Paths in this guide are relative to Rails or a Rails application unless otherwise specified.
@@ -243,7 +243,7 @@ In this file there are a lot of lines such as this inside the +ActiveSupport+ mo
autoload :Inflector
</ruby>
-Due to the overriding of the +autoload+ method, Ruby will know to look for this file at +activesupport/lib/active_support/inflector.rb+ when the +Inflector+ class is first referenced.
+Due to the overriding of the +autoload+ method, Ruby will know how to look for this file at +activesupport/lib/active_support/inflector.rb+ when the +Inflector+ class is first referenced.
The +active_support/lib/active_support/version.rb+ that is also required here simply defines an +ActiveSupport::VERSION+ constant which defines a couple of constants inside this module, the main constant of this is +ActiveSupport::VERSION::STRING+ which returns the current version of ActiveSupport.
diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile
index 69ef05104c..df7b9b364c 100644
--- a/railties/guides/source/layouts_and_rendering.textile
+++ b/railties/guides/source/layouts_and_rendering.textile
@@ -334,7 +334,7 @@ render :status => 500
render :status => :forbidden
</ruby>
-Rails understands both numeric status codes and symbols for status codes.
+Rails understands both numeric and symbolic status codes.
h6. The +:location+ Option
@@ -348,9 +348,9 @@ h5. Finding Layouts
To find the current layout, Rails first looks for a file in +app/views/layouts+ with the same base name as the controller. For example, rendering actions from the +PhotosController+ class will use +app/views/layouts/photos.html.erb+ (or +app/views/layouts/photos.builder+). If there is no such controller-specific layout, Rails will use +app/views/layouts/application.html.erb+ or +app/views/layouts/application.builder+. If there is no +.erb+ layout, Rails will use a +.builder+ layout if one exists. Rails also provides several ways to more precisely assign specific layouts to individual controllers and actions.
-h6. Specifying Layouts on a per-Controller Basis
+h6. Specifying Layouts for Controllers
-You can override the automatic layout conventions in your controllers by using the +layout+ declaration in the controller. For example:
+You can override the default layout conventions in your controllers by using the +layout+ declaration. For example:
<ruby>
class ProductsController < ApplicationController
@@ -359,9 +359,9 @@ class ProductsController < ApplicationController
end
</ruby>
-With this declaration, all methods within +ProductsController+ will use +app/views/layouts/inventory.html.erb+ for their layout.
+With this declaration, all of the methods within +ProductsController+ will use +app/views/layouts/inventory.html.erb+ for their layout.
-To assign a specific layout for the entire application, use a declaration in your +ApplicationController+ class:
+To assign a specific layout for the entire application, use a +layout+ declaration in your +ApplicationController+ class:
<ruby>
class ApplicationController < ActionController::Base
@@ -370,7 +370,7 @@ class ApplicationController < ActionController::Base
end
</ruby>
-With this declaration, all views in the entire application will use +app/views/layouts/main.html.erb+ for their layout.
+With this declaration, all of the views in the entire application will use +app/views/layouts/main.html.erb+ for their layout.
h6. Choosing Layouts at Runtime
@@ -392,9 +392,9 @@ class ProductsController < ApplicationController
end
</ruby>
-Now, if the current user is a special user, they'll get a special layout when viewing a product. You can even use an inline method to determine the layout:
+Now, if the current user is a special user, they'll get a special layout when viewing a product.
-You can also decide the layout by passing a Proc object, the block you give the Proc will be given the +controller+ instance, so you can make decisions based on the current request. For example:
+You can even use an inline method, such as a Proc, to determine the layout. For example, if you pass a Proc object, the block you give the Proc will be given the +controller+ instance, so the layout can be determined based on the current request:
<ruby>
class ProductsController < ApplicationController
@@ -404,7 +404,7 @@ end
h6. Conditional Layouts
-Layouts specified at the controller level support +:only+ and +:except+ options that take either a method name or an array of method names which correspond to method names within the controller:
+Layouts specified at the controller level support the +:only+ and +:except+ options. These options take either a method name, or an array of method names, corresponding to method names within the controller:
<ruby>
class ProductsController < ApplicationController
@@ -416,7 +416,7 @@ With this declaration, the +product+ layout would be used for everything but the
h6. Layout Inheritance
-Layouts are shared downwards in the hierarchy, and more specific layouts always override more general ones. For example:
+Layout declarations cascade downward in the hierarchy, and more specific layout declarations always override more general ones. For example:
* +application_controller.rb+
@@ -495,9 +495,9 @@ def show
end
</ruby>
-Make sure you use +and return+ and not +&amp;&amp; return+ because while the former will work, the latter will not due to operator precedence in the Ruby Language.
+Make sure to use +and return+ and not +&amp;&amp; return+, since +&amp;&amp; return+ will not work due to the operator precedence in the Ruby Language.
-Note that the implicit render done by ActionController detects if +render+ has been called, and thus avoids this error. Therefore, the following will work without errors:
+Note that the implicit render done by ActionController detects if +render+ has been called, so the following will work without errors:
<ruby>
def show
@@ -518,7 +518,7 @@ Another way to handle returning responses to an HTTP request is with +redirect_t
redirect_to photos_url
</ruby>
-You can use +redirect_to+ with any arguments that you could use with +link_to+ or +url_for+. In addition, there's a special redirect that sends the user back to the page they just came from:
+You can use +redirect_to+ with any arguments that you could use with +link_to+ or +url_for+. There's also a special redirect that sends the user back to the page they just came from:
<ruby>
redirect_to :back
@@ -526,7 +526,7 @@ redirect_to :back
h5. Getting a Different Redirect Status Code
-Rails uses HTTP status code 302 (temporary redirect) when you call +redirect_to+. If you'd like to use a different status code (perhaps 301, permanent redirect), you can do so by using the +:status+ option:
+Rails uses HTTP status code 302, a temporary redirect, when you call +redirect_to+. If you'd like to use a different status code, perhaps 301, a permanent redirect, you can use the +:status+ option:
<ruby>
redirect_to photos_path, :status => 301
@@ -536,7 +536,7 @@ Just like the +:status+ option for +render+, +:status+ for +redirect_to+ accepts
h5. The Difference Between +render+ and +redirect_to+
-Sometimes inexperienced developers conceive of +redirect_to+ as a sort of +goto+ command, moving execution from one place to another in your Rails code. This is _not_ correct. Your code stops running and waits for a new request for the browser. It just happens that you've told the browser what request it should make next, by sending back an HTTP 302 status code.
+Sometimes inexperienced developers think of +redirect_to+ as a sort of +goto+ command, moving execution from one place to another in your Rails code. This is _not_ correct. Your code stops running and waits for a new request for the browser. It just happens that you've told the browser what request it should make next, by sending back an HTTP 302 status code.
Consider these actions to see the difference:
@@ -553,7 +553,7 @@ def show
end
</ruby>
-With the code in this form, there will likely be a problem if the +@book+ variable is +nil+. Remember, a +render :action+ doesn't run any code in the target action, so nothing will set up the +@books+ variable that the +index+ view is presumably depending on. One way to fix this is to redirect instead of rendering:
+With the code in this form, there will likely be a problem if the +@book+ variable is +nil+. Remember, a +render :action+ doesn't run any code in the target action, so nothing will set up the +@books+ variable that the +index+ view will probably require. One way to fix this is to redirect instead of rendering:
<ruby>
def index
@@ -570,9 +570,9 @@ end
With this code, the browser will make a fresh request for the index page, the code in the +index+ method will run, and all will be well.
-The only downside to this code, is that it requires a round trip to the browser, the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen.
+The only downside to this code is that it requires a round trip to the browser: the browser requested the show action with +/books/1+ and the controller finds that there are no books, so the controller sends out a 302 redirect response to the browser telling it to go to +/books/+, the browser complies and sends a new request back to the controller asking now for the +index+ action, the controller then gets all the books in the database and renders the index template, sending it back down to the browser which then shows it on your screen.
-While in a small app, this added latency might not be a problem, it is something to think about when speed of response is of the essence. One way to handle this double request (though a contrived example) could be:
+While in a small application, this added latency might not be a problem, it is something to think about if response time is a concern. We can demonstrate one way to handle this with a contrived example:
<ruby>
def index
@@ -588,7 +588,7 @@ def show
end
</ruby>
-Which would detect that there are no books, populate the +@books+ instance variable with all the books in the database and then directly render the +index.html.erb+ template returning it to the browser with a flash alert message telling the user what happened.
+This would detect that there are no books with the specified ID, populate the +@books+ instance variable with all the books in the model, and then directly render the +index.html.erb+ template, returning it to the browser with a flash alert message to tell the user what happened.
h4. Using +head+ To Build Header-Only Responses
@@ -598,7 +598,7 @@ The +head+ method can be used to send responses with only headers to the browser
head :bad_request
</ruby>
-Which would produce the following header:
+This would produce the following header:
<shell>
HTTP/1.1 400 Bad Request
@@ -611,7 +611,7 @@ Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Cache-Control: no-cache
</shell>
-Or you can use other HTTP headers to convey additional information:
+Or you can use other HTTP headers to convey other information:
<ruby>
head :created, :location => photo_path(@photo)
@@ -633,15 +633,15 @@ Cache-Control: no-cache
h3. Structuring Layouts
-When Rails renders a view as a response, it does so by combining the view with the current layout (using the rules for finding the current layout that were covered earlier in this guide). Within a layout, you have access to three tools for combining different bits of output to form the overall response:
+When Rails renders a view as a response, it does so by combining the view with the current layout, using the rules for finding the current layout that were covered earlier in this guide. Within a layout, you have access to three tools for combining different bits of output to form the overall response:
* Asset tags
* +yield+ and +content_for+
* Partials
-h4. Asset Tags
+h4. Asset Tag Helpers
-Asset tags provide methods for generating HTML that links views to feeds, JavaScript, stylesheets, images, videos and audios. These are the six asset tags available in Rails:
+Asset tag helpers provide methods for generating HTML that link views to feeds, JavaScript, stylesheets, images, videos and audios. There are six asset tag helpers available in Rails:
* +auto_discovery_link_tag+
* +javascript_include_tag+
@@ -650,11 +650,11 @@ Asset tags provide methods for generating HTML that links views to feeds, JavaSc
* +video_tag+
* +audio_tag+
-You can use these tags in layouts or other views, although the tags other than +image_tag+ are most commonly used in the +&lt;head&gt;+ section of a layout.
+You can use these tags in layouts or other views, although the +auto_discovery_link_tag+, +javascript_include_tag+, and +stylesheet_link_tag+, are most commonly used in the +&lt;head&gt;+ section of a layout.
-WARNING: The asset tags do _not_ verify the existence of the assets at the specified locations; they simply assume that you know what you're doing and generate the link.
+WARNING: The asset tag helpers do _not_ verify the existence of the assets at the specified locations; they simply assume that you know what you're doing and generate the link.
-h5. Linking to Feeds with +auto_discovery_link_tag+
+h5. Linking to Feeds with the +auto_discovery_link_tag+
The +auto_discovery_link_tag+ helper builds HTML that most browsers and newsreaders can use to detect the presences of RSS or ATOM feeds. It takes the type of the link (+:rss+ or +:atom+), a hash of options that are passed through to url_for, and a hash of options for the tag:
@@ -663,13 +663,13 @@ The +auto_discovery_link_tag+ helper builds HTML that most browsers and newsread
{:title => "RSS Feed"}) %>
</erb>
-There are three tag options available for +auto_discovery_link_tag+:
+There are three tag options available for the +auto_discovery_link_tag+:
-* +:rel+ specifies the +rel+ value in the link (defaults to "alternate")
+* +:rel+ specifies the +rel+ value in the link. The default value is "alternate".
* +:type+ specifies an explicit MIME type. Rails will generate an appropriate MIME type automatically.
-* +:title+ specifies the title of the link
+* +:title+ specifies the title of the link. The default value is the upshifted +:type+ value, for example, "ATOM" or "RSS".
-h5. Linking to JavaScript Files with +javascript_include_tag+
+h5. Linking to JavaScript Files with the +javascript_include_tag+
The +javascript_include_tag+ helper returns an HTML +script+ tag for each source provided. Rails looks in +public/javascripts+ for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include +public/javascripts/main.js+:
@@ -738,7 +738,7 @@ By default, the combined file will be delivered as +javascripts/all.js+. You can
You can even use dynamic paths such as +cache/#{current_site}/main/display+.
-h5. Linking to CSS Files with +stylesheet_link_tag+
+h5. Linking to CSS Files with the +stylesheet_link_tag+
The +stylesheet_link_tag+ helper returns an HTML +&lt;link&gt;+ tag for each source provided. Rails looks in +public/stylesheets+ for these files by default, but you can specify a full path relative to the document root, or a URL, if you prefer. For example, to include +public/stylesheets/main.css+:
@@ -764,7 +764,7 @@ To include +http://example.com/main.css+:
<%= stylesheet_link_tag "http://example.com/main.css" %>
</erb>
-By default, +stylesheet_link_tag+ creates links with +media="screen" rel="stylesheet" type="text/css"+. You can override any of these defaults by specifying an appropriate option (+:media+, +:rel+, or +:type+):
+By default, the +stylesheet_link_tag+ creates links with +media="screen" rel="stylesheet" type="text/css"+. You can override any of these defaults by specifying an appropriate option (+:media+, +:rel+, or +:type+):
<erb>
<%= stylesheet_link_tag "main_print", :media => "print" %>
@@ -797,7 +797,7 @@ By default, the combined file will be delivered as +stylesheets/all.css+. You ca
You can even use dynamic paths such as +cache/#{current_site}/main/display+.
-h5. Linking to Images with +image_tag+
+h5. Linking to Images with the +image_tag+
The +image_tag+ helper builds an HTML +&lt;img /&gt;+ tag to the specified file. By default, files are loaded from +public/images+.
@@ -846,7 +846,7 @@ In addition to the above special tags, you can supply a final hash of standard H
:class => 'nav_bar' %>
</erb>
-h5. Linking to Videos with +video_tag+
+h5. Linking to Videos with the +video_tag+
The +video_tag+ helper builds an HTML 5 +&lt;video&gt;+ tag to the specified file. By default, files are loaded from +public/videos+.
@@ -882,7 +882,7 @@ This will produce:
<video><source src="trailer.ogg" /><source src="movie.ogg" /></video>
</erb>
-h5. Linking to Audio files with +audio_tag+
+h5. Linking to Audio Files with the +audio_tag+
The +audio_tag+ helper builds an HTML 5 +&lt;audio&gt;+ tag to the specified file. By default, files are loaded from +public/audios+.
@@ -933,7 +933,7 @@ You can also create a layout with multiple yielding regions:
The main body of the view will always render into the unnamed +yield+. To render content into a named +yield+, you use the +content_for+ method.
-h4. Using +content_for+
+h4. Using the +content_for+ Method
The +content_for+ method allows you to insert content into a named +yield+ block in your layout. For example, this view would work with the layout that you just saw:
diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile
index 7faa18e888..23e36b39f9 100644
--- a/railties/guides/source/migrations.textile
+++ b/railties/guides/source/migrations.textile
@@ -91,13 +91,13 @@ Active Record provides methods that perform common data definition tasks in a da
* +add_index+
* +remove_index+
-If you need to perform tasks specific to your database (for example create a "foreign key":#active-record-and-referential-integrity constraint) then the +execute+ function allows you to execute arbitrary SQL. A migration is just a regular Ruby class so you're not limited to these functions. For example after adding a column you could write code to set the value of that column for existing records (if necessary using your models).
+If you need to perform tasks specific to your database (for example create a "foreign key":#active-record-and-referential-integrity constraint) then the +execute+ method allows you to execute arbitrary SQL. A migration is just a regular Ruby class so you're not limited to these functions. For example after adding a column you could write code to set the value of that column for existing records (if necessary using your models).
On databases that support transactions with statements that change the schema (such as PostgreSQL or SQLite3), migrations are wrapped in a transaction. If the database does not support this (for example MySQL) then when a migration fails the parts of it that succeeded will not be rolled back. You will have to unpick the changes that were made by hand.
h4. What's in a Name
-Migrations are stored in files in +db/migrate+, one for each migration class. The name of the file is of the form +YYYYMMDDHHMMSS_create_products.rb+, that is to say a UTC timestamp identifying the migration followed by an underscore followed by the name of the migration. The name of the migration class (CamelCased version) should match the latter part of the file name. For example +20080906120000_create_products.rb+ should define +CreateProducts+ and +20080906120001_add_details_to_products.rb+ should define +AddDetailsToProducts+. If you do feel the need to change the file name then you <em>have to</em> update the name of the class inside or Rails will complain about a missing class.
+Migrations are stored in files in +db/migrate+, one for each migration class. The name of the file is of the form +YYYYMMDDHHMMSS_create_products.rb+, that is to say a UTC timestamp identifying the migration followed by an underscore followed by the name of the migration. The name of the migration class (CamelCased version) should match the latter part of the file name. For example +20080906120000_create_products.rb+ should define class +CreateProducts+ and +20080906120001_add_details_to_products.rb+ should define +AddDetailsToProducts+. If you do feel the need to change the file name then you <em>have to</em> update the name of the class inside or Rails will complain about a missing class.
Internally Rails only uses the migration's number (the timestamp) to identify them. Prior to Rails 2.1 the migration number started at 1 and was incremented each time a migration was generated. With multiple developers it was easy for these to clash requiring you to rollback migrations and renumber them. With Rails 2.1 this is largely avoided by using the creation time of the migration to identify them. You can revert to the old numbering scheme by adding the following line to +config/application.rb+.
@@ -115,7 +115,7 @@ h4. Changing Migrations
Occasionally you will make a mistake when writing a migration. If you have already run the migration then you cannot just edit the migration and run the migration again: Rails thinks it has already run the migration and so will do nothing when you run +rake db:migrate+. You must rollback the migration (for example with +rake db:rollback+), edit your migration and then run +rake db:migrate+ to run the corrected version.
-In general editing existing migrations is not a good idea: you will be creating extra work for yourself and your co-workers and cause major headaches if the existing version of the migration has already been run on production machines. Instead you should write a new migration that performs the changes you require. Editing a freshly generated migration that has not yet been committed to source control (or more generally which has not been propagated beyond your development machine) is relatively harmless.
+In general editing existing migrations is not a good idea: you will be creating extra work for yourself and your co-workers and cause major headaches if the existing version of the migration has already been run on production machines. Instead, you should write a new migration that performs the changes you require. Editing a freshly generated migration that has not yet been committed to source control (or, more generally, which has not been propagated beyond your development machine) is relatively harmless.
h4. Supported Types
@@ -134,7 +134,7 @@ Active Record supports the following types:
* +:binary+
* +:boolean+
-These will be mapped onto an appropriate underlying database type, for example with MySQL +:string+ is mapped to +VARCHAR(255)+. You can create columns of types not supported by Active Record when using the non-sexy syntax, for example
+These will be mapped onto an appropriate underlying database type. For example, with MySQL the type +:string+ is mapped to +VARCHAR(255)+. You can create columns of types not supported by Active Record when using the non-sexy syntax, for example
<ruby>
create_table :products do |t|
@@ -148,7 +148,7 @@ h3. Creating a Migration
h4. Creating a Model
-The model and scaffold generators will create migrations appropriate for adding a new model. This migration will already contain instructions for creating the relevant table. If you tell Rails what columns you want then statements for adding those will also be created. For example, running
+The model and scaffold generators will create migrations appropriate for adding a new model. This migration will already contain instructions for creating the relevant table. If you tell Rails what columns you want, then statements for adding these columns will also be created. For example, running
<shell>
$ rails generate model Product name:string description:text
@@ -262,7 +262,7 @@ end
which creates a +products+ table with a column called +name+ (and as discussed below, an implicit +id+ column).
-The object yielded to the block allows you to create columns on the table. There are two ways of doing this: The first (traditional) form looks like
+The object yielded to the block allows you to create columns on the table. There are two ways of doing it. The first (traditional) form looks like
<ruby>
create_table :products do |t|
@@ -270,7 +270,7 @@ create_table :products do |t|
end
</ruby>
-the second form, the so called "sexy" migration, drops the somewhat redundant +column+ method. Instead, the +string+, +integer+, etc. methods create a column of that type. Subsequent parameters are the same.
+The second form, the so called "sexy" migration, drops the somewhat redundant +column+ method. Instead, the +string+, +integer+, etc. methods create a column of that type. Subsequent parameters are the same.
<ruby>
create_table :products do |t|
@@ -278,7 +278,7 @@ create_table :products do |t|
end
</ruby>
-By default +create_table+ will create a primary key called +id+. You can change the name of the primary key with the +:primary_key+ option (don't forget to update the corresponding model) or if you don't want a primary key at all (for example for a HABTM join table) you can pass +:id => false+. If you need to pass database specific options you can place an SQL fragment in the +:options+ option. For example
+By default, +create_table+ will create a primary key called +id+. You can change the name of the primary key with the +:primary_key+ option (don't forget to update the corresponding model) or, if you don't want a primary key at all (for example for a HABTM join table), you can pass the option +:id => false+. If you need to pass database specific options you can place an SQL fragment in the +:options+ option. For example,
<ruby>
create_table :products, :options => "ENGINE=BLACKHOLE" do |t|
@@ -286,7 +286,7 @@ create_table :products, :options => "ENGINE=BLACKHOLE" do |t|
end
</ruby>
-will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table (when using MySQL the default is +ENGINE=InnoDB+).
+will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table (when using MySQL, the default is +ENGINE=InnoDB+).
h4. Changing Tables
@@ -348,11 +348,11 @@ end
</ruby>
will add an +attachment_id+ column and a string +attachment_type+ column with a default value of 'Photo'.
-NOTE: The +references+ helper does not actually create foreign key constraints for you. You will need to use +execute+ for that or a plugin that adds "foreign key support":#active-record-and-referential-integrity.
+NOTE: The +references+ helper does not actually create foreign key constraints for you. You will need to use +execute+ or a plugin that adds "foreign key support":#active-record-and-referential-integrity.
-If the helpers provided by Active Record aren't enough you can use the +execute+ function to execute arbitrary SQL.
+If the helpers provided by Active Record aren't enough you can use the +execute+ method to execute arbitrary SQL.
-For more details and examples of individual methods check the API documentation, in particular the documentation for "<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html (which provides the methods available in the +up+ and +down+ methods), "<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html (which provides the methods available on the object yielded by +create_table+) and "<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html (which provides the methods available on the object yielded by +change_table+).
+For more details and examples of individual methods, check the API documentation, in particular the documentation for "<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html (which provides the methods available in the +up+ and +down+ methods), "<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html (which provides the methods available on the object yielded by +create_table+) and "<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html (which provides the methods available on the object yielded by +change_table+).
h4. Writing Your +change+ Method
@@ -371,7 +371,7 @@ If you're going to use other methods, you'll have to write the +up+ and +down+ m
h4. Writing Your +down+ Method
-The +down+ method of your migration should revert the transformations done by the +up+ method. In other words the database schema should be unchanged if you do an +up+ followed by a +down+. For example if you create a table in the +up+ method you should drop it in the +down+ method. It is wise to do things in precisely the reverse order to in the +up+ method. For example
+The +down+ method of your migration should revert the transformations done by the +up+ method. In other words, the database schema should be unchanged if you do an +up+ followed by a +down+. For example, if you create a table in the +up+ method, you should drop it in the +down+ method. It is wise to reverse the transformations in precisely the reverse order they were made in the +up+ method. For example,
<ruby>
class ExampleMigration < ActiveRecord::Migration
@@ -402,22 +402,22 @@ class ExampleMigration < ActiveRecord::Migration
end
</ruby>
-Sometimes your migration will do something which is just plain irreversible, for example it might destroy some data. In cases like those when you can't reverse the migration you can raise +ActiveRecord::IrreversibleMigration+ from your +down+ method. If someone tries to revert your migration an error message will be displayed saying that it can't be done.
+Sometimes your migration will do something which is just plain irreversible; for example, it might destroy some data. In such cases, you can raise +ActiveRecord::IrreversibleMigration+ from your +down+ method. If someone tries to revert your migration, an error message will be displayed saying that it can't be done.
h3. Running Migrations
-Rails provides a set of rake tasks to work with migrations which boils down to running certain sets of migrations. The very first migration related rake task you use will probably be +db:migrate+. In its most basic form it just runs the +up+ method for all the migrations that have not yet been run. If there are no such migrations it exits.
+Rails provides a set of rake tasks to work with migrations which boil down to running certain sets of migrations. The very first migration related rake task you will use will probably be +db:migrate+. In its most basic form it just runs the +up+ method for all the migrations that have not yet been run. If there are no such migrations, it exits.
Note that running the +db:migrate+ also invokes the +db:schema:dump+ task, which will update your db/schema.rb file to match the structure of your database.
If you specify a target version, Active Record will run the required migrations (up or down) until it has reached the specified version. The
-version is the numerical prefix on the migration's filename. For example to migrate to version 20080906120000 run
+version is the numerical prefix on the migration's filename. For example, to migrate to version 20080906120000 run
<shell>
$ rake db:migrate VERSION=20080906120000
</shell>
-If this is greater than the current version (i.e. it is migrating upwards) this will run the +up+ method on all migrations up to and including 20080906120000, if migrating downwards this will run the +down+ method on all the migrations down to, but not including, 20080906120000.
+If version 20080906120000 is greater than the current version (i.e., it is migrating upwards), this will run the +up+ method on all migrations up to and including 20080906120000. If migrating downwards, this will run the +down+ method on all the migrations down to, but not including, 20080906120000.
h4. Rolling Back
@@ -435,13 +435,13 @@ $ rake db:rollback STEP=3
will run the +down+ method from the last 3 migrations.
-The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating back up again. As with the +db:rollback+ task you can use the +STEP+ parameter if you need to go more than one version back, for example
+The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating back up again. As with the +db:rollback+ task, you can use the +STEP+ parameter if you need to go more than one version back, for example
<shell>
$ rake db:migrate:redo STEP=3
</shell>
-Neither of these Rake tasks do anything you could not do with +db:migrate+, they are simply more convenient since you do not need to explicitly specify the version to migrate to.
+Neither of these Rake tasks do anything you could not do with +db:migrate+. They are simply more convenient, since you do not need to explicitly specify the version to migrate to.
Lastly, the +db:reset+ task will drop the database, recreate it and load the current schema into it.
@@ -449,7 +449,7 @@ NOTE: This is not the same as running all the migrations - see the section on "s
h4. Being Specific
-If you need to run a specific migration up or down the +db:migrate:up+ and +db:migrate:down+ tasks will do that. Just specify the appropriate version and the corresponding migration will have its +up+ or +down+ method invoked, for example
+If you need to run a specific migration up or down, the +db:migrate:up+ and +db:migrate:down+ tasks will do that. Just specify the appropriate version and the corresponding migration will have its +up+ or +down+ method invoked, for example,
<shell>
$ rake db:migrate:up VERSION=20080906120000
@@ -511,11 +511,11 @@ generates the following output
20080906170109 CreateProducts: migrated (10.0097s)
</shell>
-If you just want Active Record to shut up then running +rake db:migrate VERBOSE=false+ will suppress all output.
+If you just want Active Record to shut up, then running +rake db:migrate VERBOSE=false+ will suppress all output.
h3. Using Models in Your Migrations
-When creating or updating data in a migration it is often tempting to use one of your models. After all they exist to provide easy access to the underlying data. This can be done, but some caution should be observed.
+When creating or updating data in a migration it is often tempting to use one of your models. After all, they exist to provide easy access to the underlying data. This can be done, but some caution should be observed.
For example, problems occur when the model uses database columns which are (1) not currently in the database and (2) will be created by this or a subsequent migration.
@@ -524,7 +524,7 @@ Consider this example, where Alice and Bob are working on the same code base whi
Bob goes on vacation.
Alice creates a migration for the +products+ table which adds a new column and initializes it.
-She also adds a validation to the Product model for the new column.
+She also adds a validation to the +Product+ model for the new column.
<ruby>
# db/migrate/20100513121110_add_flag_to_product.rb
@@ -545,7 +545,7 @@ class Product < ActiveRecord::Base
end
</ruby>
-Alice adds a second migration which adds and initializes another column to the +products+ table and also adds a validation to the Product model for the new column.
+Alice adds a second migration which adds and initializes another column to the +products+ table and also adds a validation to the +Product+ model for the new column.
<ruby>
# db/migrate/20100515121110_add_fuzz_to_product.rb
@@ -573,7 +573,7 @@ Bob comes back from vacation and:
# updates the source - which contains both migrations and the latests version of the Product model.
# runs outstanding migrations with +rake db:migrate+, which includes the one that updates the +Product+ model.
-The migration crashes because when the model attempts to save, it tries to validate the second added column, which is not in the database when the _first_ migration runs.
+The migration crashes because when the model attempts to save, it tries to validate the second added column, which is not in the database when the _first_ migration runs:
<plain>
rake aborted!
@@ -584,7 +584,7 @@ undefined method `fuzz' for #<Product:0x000001049b14a0>
A fix for this is to create a local model within the migration. This keeps rails from running the validations, so that the migrations run to completion.
-When using a faux model, it's a good idea to call +Product.reset_column_information+ to refresh the ActiveRecord cache for the Product model prior to updating data in the database.
+When using a faux model, it's a good idea to call +Product.reset_column_information+ to refresh the +ActiveRecord+ cache for the +Product+ model prior to updating data in the database.
If Alice had done this instead, there would have been no problem:
@@ -628,7 +628,7 @@ There is no need (and it is error prone) to deploy a new instance of an app by r
For example, this is how the test database is created: the current development database is dumped (either to +db/schema.rb+ or +db/development.sql+) and then loaded into the test database.
-Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations but is all summed up in the schema file. The "annotate_models":http://agilewebdevelopment.com/plugins/annotate_models plugin, which automatically adds (and updates) comments at the top of each model summarizing the schema, may also be of interest.
+Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations, but is summed up in the schema file. The "annotate_models":https://github.com/ctran/annotate_models gem automatically adds and updates comments at the top of each model summarizing the schema if you desire that functionality.
h4. Types of Schema Dumps
@@ -654,13 +654,11 @@ ActiveRecord::Schema.define(:version => 20080906171750) do
end
</ruby>
-In many ways this is exactly what it is. This file is created by inspecting the database and expressing its structure using +create_table+, +add_index+, and so on. Because this is database independent it could be loaded into any database that Active Record supports. This could be very useful if you were to distribute an application that is able to run against multiple databases.
+In many ways this is exactly what it is. This file is created by inspecting the database and expressing its structure using +create_table+, +add_index+, and so on. Because this is database-independent, it could be loaded into any database that Active Record supports. This could be very useful if you were to distribute an application that is able to run against multiple databases.
-There is however a trade-off: +db/schema.rb+ cannot express database specific items such as foreign key constraints, triggers or stored procedures. While in a migration you can execute custom SQL statements, the schema dumper cannot reconstitute those statements from the database. If you are using features like this then you should set the schema format to +:sql+.
+There is however a trade-off: +db/schema.rb+ cannot express database specific items such as foreign key constraints, triggers, or stored procedures. While in a migration you can execute custom SQL statements, the schema dumper cannot reconstitute those statements from the database. If you are using features like this, then you should set the schema format to +:sql+.
-Instead of using Active Record's schema dumper the database's structure will be dumped using a tool specific to that database (via the +db:structure:dump+ Rake task) into +db/#{Rails.env}_structure.sql+. For example for PostgreSQL the +pg_dump+ utility is used and for MySQL this file will contain the output of +SHOW CREATE TABLE+ for the various tables. Loading this schema is simply a question of executing the SQL statements contained inside.
-
-By definition this will be a perfect copy of the database's structure but this will usually prevent loading the schema into a database other than the one used to create it.
+Instead of using Active Record's schema dumper, the database's structure will be dumped using a tool specific to the database (via the +db:structure:dump+ Rake task) into +db/#{Rails.env}_structure.sql+. For example, for the PostgreSQL RDBMS, the +pg_dump+ utility is used. For MySQL, this file will contain the output of +SHOW CREATE TABLE+ for the various tables. Loading these schemas is simply a question of executing the SQL statements they contain. By definition, this will create a perfect copy of the database's structure. Using the +:sql+ schema format will, however, prevent loading the schema into a RDBMS other than the one used to create it.
h4. Schema Dumps and Source Control
@@ -670,6 +668,6 @@ h3. Active Record and Referential Integrity
The Active Record way claims that intelligence belongs in your models, not in the database. As such, features such as triggers or foreign key constraints, which push some of that intelligence back into the database, are not heavily used.
-Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level these cannot guarantee referential integrity and so some people augment them with foreign key constraints.
+Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level, these cannot guarantee referential integrity and so some people augment them with foreign key constraints.
Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. There are also a number of plugins such as "foreign_key_migrations":https://github.com/harukizaemon/redhillonrails/tree/master/foreign_key_migrations/ which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+).
diff --git a/railties/guides/source/rails_on_rack.textile b/railties/guides/source/rails_on_rack.textile
index 57c03b54dc..d6cbd84b1f 100644
--- a/railties/guides/source/rails_on_rack.textile
+++ b/railties/guides/source/rails_on_rack.textile
@@ -166,8 +166,9 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol
|+Rack::Lock+|Sets <tt>env["rack.multithread"]</tt> flag to +true+ and wraps the application within a Mutex.|
|+ActionController::Failsafe+|Returns HTTP Status +500+ to the client if an exception gets raised while dispatching.|
|+ActiveRecord::QueryCache+|Enables the Active Record query cache.|
-|+ActionController::Session::CookieStore+|Uses the cookie based session store.|
-|+ActionController::Session::MemCacheStore+|Uses the memcached based session store.|
+|+ActionDispatch::Session::CookieStore+|Uses the cookie based session store.|
+|+ActionDispatch::Session::CacheStore+|Uses the Rails cache based session store.|
+|+ActionDispatch::Session::MemCacheStore+|Uses the memcached based session store.|
|+ActiveRecord::SessionStore+|Uses the database based session store.|
|+Rack::MethodOverride+|Sets HTTP method based on +_method+ parameter or <tt>env["HTTP_X_HTTP_METHOD_OVERRIDE"]</tt>.|
|+Rack::Head+|Discards the response body if the client sends a +HEAD+ request.|
diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile
index 0a9f1e8388..f281009fee 100644
--- a/railties/guides/source/routing.textile
+++ b/railties/guides/source/routing.textile
@@ -596,6 +596,8 @@ match "/stories/:name" => redirect {|params| "/posts/#{params[:name].pluralize}"
match "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" }
</ruby>
+Please note that this redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible.
+
In all of these cases, if you don't provide the leading host (+http://www.example.com+), Rails will take those details from the current request.
h4. Routing to Rack Applications
diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile
index 73c7a80ff6..a499ef3d39 100644
--- a/railties/guides/source/security.textile
+++ b/railties/guides/source/security.textile
@@ -82,9 +82,9 @@ This will also be a good idea, if you modify the structure of an object and old
h4. Session Storage
--- _Rails provides several storage mechanisms for the session hashes. The most important are ActiveRecordStore and CookieStore._
+-- _Rails provides several storage mechanisms for the session hashes. The most important are ActiveRecord::SessionStore and ActionDispatch::Session::CookieStore._
-There are a number of session storages, i.e. where Rails saves the session hash and session id. Most real-live applications choose ActiveRecordStore (or one of its derivatives) over file storage due to performance and maintenance reasons. ActiveRecordStore keeps the session id and hash in a database table and saves and retrieves the hash on every request.
+There are a number of session storages, i.e. where Rails saves the session hash and session id. Most real-live applications choose ActiveRecord::SessionStore (or one of its derivatives) over file storage due to performance and maintenance reasons. ActiveRecord::SessionStore keeps the session id and hash in a database table and saves and retrieves the hash on every request.
Rails 2 introduced a new default session storage, CookieStore. CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. That will greatly increase the speed of the application, but it is a controversial storage option and you have to think about the security implications of it:
@@ -157,9 +157,9 @@ One possibility is to set the expiry time-stamp of the cookie with the session i
<ruby>
class Session < ActiveRecord::Base
def self.sweep(time = 1.hour)
- time = time.split.inject { |count, unit|
- count.to_i.send(unit)
- } if time.is_a?(String)
+ if time.is_a?(String)
+ time = time.split.inject { |count, unit| count.to_i.send(unit) }
+ end
delete_all "updated_at < '#{time.ago.to_s(:db)}'"
end
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 2e412147d3..82fffe86bb 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -91,7 +91,7 @@ module Rails
@routes_reloader ||= RoutesReloader.new
end
- def initialize!(group=nil)
+ def initialize!(group=:default)
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
@@ -164,7 +164,8 @@ module Rails
middleware.use ::Rack::Lock unless config.allow_concurrency
middleware.use ::Rack::Runtime
middleware.use ::Rack::MethodOverride
- middleware.use ::Rails::Rack::Logger # must come after Rack::MethodOverride to properly log overridden methods
+ middleware.use ::ActionDispatch::RequestId
+ middleware.use ::Rails::Rack::Logger, config.log_tags # must come after Rack::MethodOverride to properly log overridden methods
middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local
middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
if config.action_dispatch.x_sendfile_header.present?
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 0aff05b681..c2cb121e42 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -24,12 +24,12 @@ module Rails
initializer :initialize_logger, :group => :all do
Rails.logger ||= config.logger || begin
path = config.paths["log"].first
- logger = ActiveSupport::BufferedLogger.new(path)
+ logger = ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(path))
logger.level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase)
logger.auto_flushing = false if Rails.env.production?
logger
rescue StandardError
- logger = ActiveSupport::BufferedLogger.new(STDERR)
+ logger = ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(STDERR))
logger.level = ActiveSupport::BufferedLogger::WARN
logger.warn(
"Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " +
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index c363e53c10..8f5b28faf8 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -8,7 +8,7 @@ module Rails
attr_accessor :allow_concurrency, :asset_host, :asset_path, :assets,
:cache_classes, :cache_store, :consider_all_requests_local,
:dependency_loading, :filter_parameters,
- :force_ssl, :helpers_paths, :logger, :preload_frameworks,
+ :force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks,
:reload_plugins, :secret_token, :serve_static_assets,
:ssl_options, :static_cache_control, :session_options,
:time_zone, :whiny_nils
@@ -37,19 +37,20 @@ module Rails
@cache_store = [ :file_store, "#{root}/tmp/cache/" ]
@assets = ActiveSupport::OrderedOptions.new
- @assets.enabled = false
- @assets.paths = []
- @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) },
- /(?:\/|\\|\A)application\.(css|js)$/ ]
- @assets.prefix = "/assets"
- @assets.version = ''
- @assets.debug = false
- @assets.compile = true
- @assets.digest = false
- @assets.manifest = nil
- @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ]
- @assets.js_compressor = nil
- @assets.css_compressor = nil
+ @assets.enabled = false
+ @assets.paths = []
+ @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) },
+ /(?:\/|\\|\A)application\.(css|js)$/ ]
+ @assets.prefix = "/assets"
+ @assets.version = ''
+ @assets.debug = false
+ @assets.compile = true
+ @assets.digest = false
+ @assets.manifest = nil
+ @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ]
+ @assets.js_compressor = nil
+ @assets.css_compressor = nil
+ @assets.initialize_on_precompile = true
end
def compiled_asset_path
diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb
index 1cf23a8b92..60d1aed73a 100644
--- a/railties/lib/rails/commands/application.rb
+++ b/railties/lib/rails/commands/application.rb
@@ -9,6 +9,14 @@ if ARGV.first != "new"
ARGV[0] = "--help"
else
ARGV.shift
+ railsrc = File.join(File.expand_path("~"), ".railsrc")
+ if File.exist?(railsrc)
+ extra_args_string = File.open(railsrc).read
+ extra_args = extra_args_string.split(/\n+/).map {|l| l.split}.flatten
+ puts "Using #{extra_args.join(" ")} from #{railsrc}"
+ ARGV << extra_args
+ ARGV.flatten!
+ end
end
require 'rubygems' if ARGV.include?("--dev")
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index 23392276d5..20484a10c8 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -78,7 +78,7 @@ module Rails
middlewares = []
middlewares << [Rails::Rack::LogTailer, log_path] unless options[:daemonize]
middlewares << [Rails::Rack::Debugger] if options[:debugger]
- middlewares << [Rails::Rack::ContentLength]
+ middlewares << [::Rack::ContentLength]
Hash.new(middlewares)
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 0e1e719596..2d25273050 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -542,7 +542,7 @@ module Rails
require environment if environment
end
- initializer :append_assets_path, :group => :assets do |app|
+ initializer :append_assets_path, :group => :all do |app|
app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["app/assets"].existent_directories)
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 575f4bb106..b26839644e 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -90,7 +90,7 @@ module Rails
append_file "Gemfile", "\ngroup #{name} do\n", :force => true
@in_group = true
- instance_eval &block
+ instance_eval(&block)
@in_group = false
append_file "Gemfile", "end\n", :force => true
@@ -252,7 +252,7 @@ module Rails
#
def rake(command, options={})
log :rake, command
- env = options[:env] || 'development'
+ env = options[:env] || ENV["RAILS_ENV"] || 'development'
sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) }
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 294563ad06..10fdfdd8a9 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -138,7 +138,7 @@ module Rails
if options.dev?
<<-GEMFILE.strip_heredoc
gem 'rails', :path => '#{Rails::Generators::RAILS_DEV_PATH}'
- gem 'journey', :path => '#{Rails::Generators::JOURNEY_DEV_PATH}'
+ gem 'journey', :git => 'git://github.com/rails/journey.git'
GEMFILE
elsif options.edge?
<<-GEMFILE.strip_heredoc
@@ -150,7 +150,7 @@ module Rails
gem 'rails', '#{Rails::VERSION::STRING}'
# Bundle edge Rails instead:
- # gem 'rails', :git => 'git://github.com/rails/rails.git'
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
GEMFILE
end
end
@@ -158,11 +158,11 @@ module Rails
def gem_for_database
# %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql )
case options[:database]
- when "oracle" then "ruby-oci8"
- when "postgresql" then "pg"
- when "frontbase" then "ruby-frontbase"
- when "mysql" then "mysql2"
- when "sqlserver" then "activerecord-sqlserver-adapter"
+ when "oracle" then "ruby-oci8"
+ when "postgresql" then "pg"
+ when "frontbase" then "ruby-frontbase"
+ when "mysql" then "mysql2"
+ when "sqlserver" then "activerecord-sqlserver-adapter"
when "jdbcmysql" then "activerecord-jdbcmysql-adapter"
when "jdbcsqlite3" then "activerecord-jdbcsqlite3-adapter"
when "jdbcpostgresql" then "activerecord-jdbcpostgresql-adapter"
@@ -190,17 +190,6 @@ module Rails
end
end
- def turn_gemfile_entry
- unless RUBY_VERSION < "1.9.2" || options[:skip_test_unit]
- <<-GEMFILE.strip_heredoc
- group :test do
- # Pretty printed test output
- gem 'turn', :require => false
- end
- GEMFILE
- end
- end
-
def assets_gemfile_entry
<<-GEMFILE.strip_heredoc
# Gems used only for assets and not required
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index b9dc31457a..911f80cf3a 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -91,7 +91,7 @@ module Rails
#
# The lookup in this case for test_unit as input is:
#
- # "test_unit:awesome", "test_unit"
+ # "test_framework:awesome", "test_framework"
#
# Which is not the desired the lookup. You can change it by providing the
# :as option:
@@ -102,7 +102,7 @@ module Rails
#
# And now it will lookup at:
#
- # "test_unit:controller", "test_unit"
+ # "test_framework:controller", "test_framework"
#
# Similarly, if you want it to also lookup in the rails namespace, you just
# need to provide the :base value:
@@ -113,7 +113,7 @@ module Rails
#
# And the lookup is exactly the same as previously:
#
- # "rails:test_unit", "test_unit:controller", "test_unit"
+ # "rails:test_framework", "test_framework:controller", "test_framework"
#
# ==== Switches
#
diff --git a/railties/lib/rails/generators/rails/app/USAGE b/railties/lib/rails/generators/rails/app/USAGE
index 9e7a78d132..691095f33f 100644
--- a/railties/lib/rails/generators/rails/app/USAGE
+++ b/railties/lib/rails/generators/rails/app/USAGE
@@ -2,6 +2,12 @@ Description:
The 'rails new' command creates a new Rails application with a default
directory structure and configuration at the path you specify.
+ You can specify extra command-line arguments to be used every time
+ 'rails new' runs in the .railsrc configuration file in your home directory.
+
+ Note that the arguments specified in the .railsrc file don't affect the
+ defaults values shown above in this help message.
+
Example:
rails new ~/Code/Ruby/weblog
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 9cbda6649d..3e32f758a4 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -122,10 +122,15 @@ module Rails
end
def vendor
+ vendor_javascripts
vendor_stylesheets
vendor_plugins
end
+ def vendor_javascripts
+ empty_directory_with_gitkeep "vendor/assets/javascripts"
+ end
+
def vendor_stylesheets
empty_directory_with_gitkeep "vendor/assets/stylesheets"
end
@@ -139,8 +144,6 @@ module Rails
# We need to store the RAILS_DEV_PATH in a constant, otherwise the path
# can change in Ruby 1.8.7 when we FileUtils.cd.
RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
- JOURNEY_DEV_PATH = File.expand_path("../../../../../../../journey", File.dirname(__FILE__))
-
RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test]
class AppGenerator < AppBase
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 910cd16950..d3b8f4d595 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -21,5 +21,3 @@ source 'http://rubygems.org'
# To use debugger
# <%= ruby_debugger_gemfile_entry %>
-
-<%= turn_gemfile_entry -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 64e2c09467..50f2df3d35 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -33,8 +33,11 @@
# See everything in the log (default is :info)
# config.log_level = :debug
+ # Prepend all log lines with the following tags
+ # config.log_tags = [ :subdomain, :uuid ]
+
# Use a different logger for distributed setups
- # config.logger = SyslogLogger.new
+ # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production
# config.cache_store = :mem_cache_store
diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore
index 923b697662..eb3489a986 100644
--- a/railties/lib/rails/generators/rails/app/templates/gitignore
+++ b/railties/lib/rails/generators/rails/app/templates/gitignore
@@ -1,5 +1,15 @@
-.bundle
-db/*.sqlite3
-log/*.log
-tmp/
-.sass-cache/
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile ~/.gitignore_global
+
+# Ignore bundler config
+/.bundle
+
+# Ignore the default SQLite database.
+/db/*.sqlite3
+
+# Ignore all logfiles and tempfiles.
+/log/*.log
+/tmp
diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb
index de01c858dd..b34bc4a524 100644
--- a/railties/lib/rails/generators/resource_helpers.rb
+++ b/railties/lib/rails/generators/resource_helpers.rb
@@ -65,7 +65,7 @@ module Rails
begin
"#{options[:orm].to_s.classify}::Generators::ActiveModel".constantize
- rescue NameError => e
+ rescue NameError
Rails::Generators::ActiveModel
end
end
diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb
index 4c1da0a5a5..04d5b55c69 100644
--- a/railties/lib/rails/initializable.rb
+++ b/railties/lib/rails/initializable.rb
@@ -10,6 +10,7 @@ module Rails
attr_reader :name, :block
def initialize(name, context, options, &block)
+ options[:group] ||= :default
@name, @context, @options, @block = name, context, options, block
end
@@ -48,10 +49,10 @@ module Rails
end
end
- def run_initializers(group=nil, *args)
+ def run_initializers(group=:default, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort.each do |initializer|
- initializer.run(*args) if group.nil? || initializer.belongs_to?(group)
+ initializer.run(*args) if initializer.belongs_to?(group)
end
@ran = true
end
diff --git a/railties/lib/rails/rack.rb b/railties/lib/rails/rack.rb
index d4a41b217e..d1ee96f7fd 100644
--- a/railties/lib/rails/rack.rb
+++ b/railties/lib/rails/rack.rb
@@ -1,6 +1,5 @@
module Rails
module Rack
- autoload :ContentLength, "rails/rack/content_length"
autoload :Debugger, "rails/rack/debugger"
autoload :Logger, "rails/rack/logger"
autoload :LogTailer, "rails/rack/log_tailer"
diff --git a/railties/lib/rails/rack/content_length.rb b/railties/lib/rails/rack/content_length.rb
deleted file mode 100644
index 6839af4152..0000000000
--- a/railties/lib/rails/rack/content_length.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'action_dispatch'
-require 'rack/utils'
-
-module Rails
- module Rack
- # Sets the Content-Length header on responses with fixed-length bodies.
- class ContentLength
- include ::Rack::Utils
-
- def initialize(app, sendfile=nil)
- @app = app
- @sendfile = sendfile
- end
-
- def call(env)
- status, headers, body = @app.call(env)
- headers = HeaderHash.new(headers)
-
- if !STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i) &&
- !headers['Content-Length'] &&
- !headers['Transfer-Encoding'] &&
- !(@sendfile && headers[@sendfile])
-
- old_body = body
- body, length = [], 0
- old_body.each do |part|
- body << part
- length += bytesize(part)
- end
- old_body.close if old_body.respond_to?(:close)
- headers['Content-Length'] = length.to_s
- end
-
- [status, headers, body]
- end
- end
- end
-end \ No newline at end of file
diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb
index 3be262de08..89de10c83d 100644
--- a/railties/lib/rails/rack/logger.rb
+++ b/railties/lib/rails/rack/logger.rb
@@ -1,32 +1,46 @@
require 'active_support/core_ext/time/conversions'
+require 'active_support/core_ext/object/blank'
module Rails
module Rack
# Log the request started and flush all loggers after it.
class Logger < ActiveSupport::LogSubscriber
- def initialize(app)
- @app = app
+ def initialize(app, tags=nil)
+ @app, @tags = app, tags.presence
end
def call(env)
- before_dispatch(env)
- @app.call(env)
- ensure
- after_dispatch(env)
+ if @tags
+ Rails.logger.tagged(compute_tags(env)) { call_app(env) }
+ else
+ call_app(env)
+ end
end
protected
- def before_dispatch(env)
+ def call_app(env)
request = ActionDispatch::Request.new(env)
path = request.filtered_path
-
- info "\n\nStarted #{request.request_method} \"#{path}\" " \
- "for #{request.ip} at #{Time.now.to_default_s}"
+ Rails.logger.info "\n\nStarted #{request.request_method} \"#{path}\" for #{request.ip} at #{Time.now.to_default_s}"
+ @app.call(env)
+ ensure
+ ActiveSupport::LogSubscriber.flush_all!
end
- def after_dispatch(env)
- ActiveSupport::LogSubscriber.flush_all!
+ def compute_tags(env)
+ request = ActionDispatch::Request.new(env)
+
+ @tags.collect do |tag|
+ case tag
+ when Proc
+ tag.call(request)
+ when Symbol
+ request.send(tag)
+ else
+ tag
+ end
+ end
end
end
end
diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake
index 2152e811f5..eea8abe7d2 100644
--- a/railties/lib/rails/tasks/engine.rake
+++ b/railties/lib/rails/tasks/engine.rake
@@ -2,6 +2,7 @@ task "load_app" do
namespace :app do
load APP_RAKEFILE
end
+ task :environment => "app:environment"
if !defined?(ENGINE_PATH) || !ENGINE_PATH
ENGINE_PATH = find_engine_path(APP_RAKEFILE)
diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake
index 8b4775d1d3..0dcca36d8b 100644
--- a/railties/lib/rails/tasks/misc.rake
+++ b/railties/lib/rails/tasks/misc.rake
@@ -1,5 +1,3 @@
-task :default => :test
-
task :rails_env do
# TODO Do we really need this?
unless defined? RAILS_ENV
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index 68f566274d..8d0d8cacac 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -24,7 +24,7 @@ if defined?(MiniTest)
end
end
-if defined?(ActiveRecord)
+if defined?(ActiveRecord::Base)
require 'active_record/test_case'
class ActiveSupport::TestCase
diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake
index 33da2c0f5a..fa01f42c5b 100644
--- a/railties/lib/rails/test_unit/testing.rake
+++ b/railties/lib/rails/test_unit/testing.rake
@@ -71,6 +71,8 @@ module Kernel
end
end
+task :default => :test
+
desc 'Runs test:units, test:functionals, test:integration together (also available: test:benchmark, test:profile, test:plugins)'
task :test do
tests_to_run = ENV['TEST'] ? ["test:single"] : %w(test:units test:functionals test:integration)
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index 118ffff44b..d4ffbe3d66 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -22,13 +22,13 @@ module ApplicationTests
end
def precompile!
- capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
end
end
test "assets routes have higher priority" do
- app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
+ app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;"
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
@@ -39,7 +39,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
get "/assets/demo.js"
- assert_match "alert()", last_response.body
+ assert_equal 'a = "/assets/rails.png";', last_response.body.strip
end
test "assets do not require compressors until it is used" do
@@ -244,14 +244,16 @@ module ApplicationTests
assert_match(/app.js isn't precompiled/, last_response.body)
end
- test "precompile appends the md5 hash to files referenced with asset_path and run in the provided RAILS_ENV" do
+ test "precompile properly refers files referenced with asset_path and and run in the provided RAILS_ENV" do
app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
# digest is default in false, we must enable it for test environment
- add_to_config "config.assets.digest = true"
+ add_to_env_config "test", "config.assets.digest = true"
- # capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_ENV=test` }
- # end
+ end
+ file = Dir["#{app_path}/public/assets/application.css"].first
+ assert_match(/\/assets\/rails\.png/, File.read(file))
file = Dir["#{app_path}/public/assets/application-*.css"].first
assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
end
@@ -279,7 +281,7 @@ module ApplicationTests
add_to_config "config.assets.compile = true"
ENV["RAILS_ENV"] = nil
- capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_GROUPS=assets` }
end
file = Dir["#{app_path}/public/assets/application-*.css"].first
@@ -287,16 +289,16 @@ module ApplicationTests
end
test "precompile should handle utf8 filenames" do
- app_file "app/assets/images/レイルズ.png", "not a image really"
- add_to_config "config.assets.precompile = [ /\.png$$/, /application.(css|js)$/ ]"
+ filename = "レイルズ.png"
+ app_file "app/assets/images/#{filename}", "not a image really"
+ add_to_config "config.assets.precompile = [ /\.png$/, /application.(css|js)$/ ]"
precompile!
- assert File.exists?("#{app_path}/public/assets/レイルズ.png")
-
- manifest = "#{app_path}/public/assets/manifest.yml"
+ require "#{app_path}/config/environment"
- assets = YAML.load_file(manifest)
- assert_equal "レイルズ.png", assets["レイルズ.png"]
+ get "/assets/#{URI.parser.escape(filename)}"
+ assert_match "not a image really", last_response.body
+ assert File.exists?("#{app_path}/public/assets/#{filename}")
end
test "assets are cleaned up properly" do
@@ -304,7 +306,7 @@ module ApplicationTests
app_file "public/assets/application.css", "a { color: green; }"
app_file "public/assets/subdir/broken.png", "not really an image file"
- capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:clean` }
end
@@ -395,7 +397,62 @@ module ApplicationTests
assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
end
+ test "assets can access model information when precompiling" do
+ app_file "app/models/post.rb", "class Post; end"
+ app_file "app/assets/javascripts/application.js", "//= require_tree ."
+ app_file "app/assets/javascripts/xmlhr.js.erb", "<%= Post.name %>"
+
+ add_to_config "config.assets.digest = false"
+ precompile!
+ assert_equal "Post;\n", File.read("#{app_path}/public/assets/application.js")
+ end
+
+ test "assets can't access model information when precompiling if not initializing the app" do
+ app_file "app/models/post.rb", "class Post; end"
+ app_file "app/assets/javascripts/application.js", "//= require_tree ."
+ app_file "app/assets/javascripts/xmlhr.js.erb", "<%= defined?(Post) || :NoPost %>"
+
+ add_to_config "config.assets.digest = false"
+ add_to_config "config.assets.initialize_on_precompile = false"
+
+ precompile!
+ assert_equal "NoPost;\n", File.read("#{app_path}/public/assets/application.js")
+ end
+
+ test "enhancements to assets:precompile should only run once" do
+ app_file "lib/tasks/enhance.rake", "Rake::Task['assets:precompile'].enhance { puts 'enhancement' }"
+ output = precompile!
+ assert_equal 1, output.scan("enhancement").size
+ end
+
+ test "digested assets are not mistakenly removed" do
+ app_file "app/assets/application.js", "alert();"
+ add_to_config "config.assets.compile = true"
+ add_to_config "config.assets.digest = true"
+
+ quietly do
+ Dir.chdir(app_path){ `bundle exec rake assets:clean assets:precompile` }
+ end
+
+ files = Dir["#{app_path}/public/assets/application-*.js"]
+ assert_equal 1, files.length, "Expected digested application.js asset to be generated, but none found"
+ end
+
+ test "digested assets are removed from configured path" do
+ app_file "public/production_assets/application.js", "alert();"
+ add_to_env_config "production", "config.assets.prefix = 'production_assets'"
+
+ ENV["RAILS_ENV"] = nil
+ quietly do
+ Dir.chdir(app_path){ `bundle exec rake assets:clean` }
+ end
+
+ files = Dir["#{app_path}/public/production_assets/application.js"]
+ assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists"
+ end
+
private
+
def app_with_assets_in_view
app_file "app/assets/javascripts/application.js", "//= require_tree ."
app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }"
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 448982f9de..97ad47ac14 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -306,7 +306,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors")
end
@@ -319,7 +319,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors")
end
@@ -332,7 +332,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers")
end
@@ -345,7 +345,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailObserver, ::MyOtherMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers")
end
diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb
index e656ada3c0..050a2161ae 100644
--- a/railties/test/application/middleware/cache_test.rb
+++ b/railties/test/application/middleware/cache_test.rb
@@ -31,6 +31,10 @@ module ApplicationTests
$last_modified ||= Time.now.utc
render_conditionally(:last_modified => $last_modified)
end
+
+ def keeps_if_modified_since
+ render :text => request.headers['If-Modified-Since']
+ end
private
def render_conditionally(headers)
if stale?(headers.merge(:public => !params[:private]))
@@ -47,6 +51,16 @@ module ApplicationTests
RUBY
end
+ def test_cache_keeps_if_modified_since
+ simple_controller
+ expected = "Wed, 30 May 1984 19:43:31 GMT"
+
+ get "/expires/keeps_if_modified_since", {}, "HTTP_IF_MODIFIED_SINCE" => expected
+
+ assert_equal 200, last_response.status
+ assert_equal expected, last_response.body, "cache should have kept If-Modified-Since"
+ end
+
def test_cache_is_disabled_in_dev_mode
simple_controller
app("development")
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index 093cb6ca2a..4703a59326 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -30,6 +30,7 @@ module ApplicationTests
"ActiveSupport::Cache::Strategy::LocalCache",
"Rack::Runtime",
"Rack::MethodOverride",
+ "ActionDispatch::RequestId",
"Rails::Rack::Logger", # must come after Rack::MethodOverride to properly log overridden methods
"ActionDispatch::ShowExceptions",
"ActionDispatch::RemoteIp",
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 94e9abb3cc..51fa2fe16f 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -179,9 +179,12 @@ class ActionsTest < Rails::Generators::TestCase
action :generate, 'model', 'MyModel'
end
- def test_rake_should_run_rake_command_with_development_env
- generator.expects(:run).once.with('rake log:clear RAILS_ENV=development', :verbose => false)
+ def test_rake_should_run_rake_command_with_default_env
+ generator.expects(:run).once.with("rake log:clear RAILS_ENV=development", :verbose => false)
+ old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil
action :rake, 'log:clear'
+ ensure
+ ENV["RAILS_ENV"] = old_env
end
def test_rake_with_env_option_should_run_rake_command_in_env
@@ -189,9 +192,28 @@ class ActionsTest < Rails::Generators::TestCase
action :rake, 'log:clear', :env => 'production'
end
+ def test_rake_with_rails_env_variable_should_run_rake_command_in_env
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
+ old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production"
+ action :rake, 'log:clear'
+ ensure
+ ENV["RAILS_ENV"] = old_env
+ end
+
+ def test_env_option_should_win_over_rails_env_variable_when_running_rake
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
+ old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "staging"
+ action :rake, 'log:clear', :env => 'production'
+ ensure
+ ENV["RAILS_ENV"] = old_env
+ end
+
def test_rake_with_sudo_option_should_run_rake_command_with_sudo
- generator.expects(:run).once.with('sudo rake log:clear RAILS_ENV=development', :verbose => false)
+ generator.expects(:run).once.with("sudo rake log:clear RAILS_ENV=development", :verbose => false)
+ old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil
action :rake, 'log:clear', :sudo => true
+ ensure
+ ENV["RAILS_ENV"] = old_env
end
def test_capify_should_run_the_capify_command
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 1b48c80042..4b74bd6a4b 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -203,6 +203,16 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file 'test'
end
+ def test_creation_of_vendor_assets_javascripts_directory
+ run_generator
+ assert_file "vendor/assets/javascripts"
+ end
+
+ def test_creation_of_vendor_assets_stylesheets_directory
+ run_generator
+ assert_file "vendor/assets/stylesheets"
+ end
+
def test_jquery_is_the_default_javascript_library
run_generator
assert_file "app/assets/javascripts/application.js" do |contents|
@@ -232,21 +242,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
- def test_inclusion_of_turn_gem_in_gemfile
- run_generator
- assert_file "Gemfile" do |contents|
- assert_match(/gem 'turn'/, contents) unless RUBY_VERSION < '1.9.2'
- assert_no_match(/gem 'turn'/, contents) if RUBY_VERSION < '1.9.2'
- end
- end
-
- def test_turn_gem_is_not_included_in_gemfile_if_skipping_test_unit
- run_generator [destination_root, "--skip-test-unit"]
- assert_file "Gemfile" do |contents|
- assert_no_match(/gem 'turn'/, contents) unless RUBY_VERSION < '1.9.2'
- end
- end
-
def test_inclusion_of_ruby_debug
run_generator
assert_file "Gemfile" do |contents|
diff --git a/railties/test/generators/assets_generator_test.rb b/railties/test/generators/assets_generator_test.rb
index 044e0b6bc6..d6338bd3da 100644
--- a/railties/test/generators/assets_generator_test.rb
+++ b/railties/test/generators/assets_generator_test.rb
@@ -13,7 +13,7 @@ class AssetsGeneratorTest < Rails::Generators::TestCase
end
def test_skipping_assets
- content = run_generator ["posts", "--no-stylesheets", "--no-javascripts"]
+ run_generator ["posts", "--no-stylesheets", "--no-javascripts"]
assert_no_file "app/assets/javascripts/posts.js"
assert_no_file "app/assets/stylesheets/posts.css"
end
diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb
index 1dbcc249ab..c84c7f204c 100644
--- a/railties/test/initializable_test.rb
+++ b/railties/test/initializable_test.rb
@@ -209,7 +209,7 @@ module InitializableTests
$arr = []
instance = Instance.new
instance.run_initializers
- assert_equal [1, 2, 3, 4], $arr
+ assert_equal [2, 3, 4], $arr
end
test "running locals with groups" do
@@ -223,7 +223,7 @@ module InitializableTests
class WithArgsTest < ActiveSupport::TestCase
test "running initializers with args" do
$with_arg = nil
- WithArgs.new.run_initializers(nil, 'foo')
+ WithArgs.new.run_initializers(:default, 'foo')
assert_equal 'foo', $with_arg
end
end
diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb
index 21fde49ff7..7653e52d26 100644
--- a/railties/test/railties/shared_tests.rb
+++ b/railties/test/railties/shared_tests.rb
@@ -21,6 +21,23 @@ module RailtiesTest
assert_match "alert()", last_response.body
end
+ def test_rake_environment_can_be_called_in_the_engine_or_plugin
+ boot_rails
+
+ @plugin.write "Rakefile", <<-RUBY
+ APP_RAKEFILE = '#{app_path}/Rakefile'
+ load 'rails/tasks/engine.rake'
+ task :foo => :environment do
+ puts "Task ran"
+ end
+ RUBY
+
+ Dir.chdir(@plugin.path) do
+ output = `bundle exec rake foo`
+ assert_match "Task ran", output
+ end
+ end
+
def test_copying_migrations
@plugin.write "db/migrate/1_create_users.rb", <<-RUBY
class CreateUsers < ActiveRecord::Migration