aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
Diffstat (limited to 'railties')
-rw-r--r--railties/CHANGELOG.md6
-rw-r--r--railties/guides/code/getting_started/README.rdoc (renamed from railties/guides/code/getting_started/README)0
-rw-r--r--railties/guides/code/getting_started/config/environments/development.rb7
-rw-r--r--railties/guides/code/getting_started/config/environments/production.rb4
-rw-r--r--railties/guides/source/action_controller_overview.textile2
-rw-r--r--railties/guides/source/active_record_querying.textile36
-rw-r--r--railties/guides/source/active_support_core_extensions.textile12
-rw-r--r--railties/guides/source/asset_pipeline.textile14
-rw-r--r--railties/guides/source/caching_with_rails.textile8
-rw-r--r--railties/guides/source/command_line.textile10
-rw-r--r--railties/guides/source/configuring.textile8
-rw-r--r--railties/guides/source/contributing_to_ruby_on_rails.textile2
-rw-r--r--railties/guides/source/debugging_rails_applications.textile2
-rw-r--r--railties/guides/source/getting_started.textile2
-rw-r--r--railties/guides/source/i18n.textile2
-rw-r--r--railties/guides/source/layouts_and_rendering.textile63
-rw-r--r--railties/guides/source/migrations.textile533
-rw-r--r--railties/guides/source/performance_testing.textile2
-rw-r--r--railties/guides/source/rails_on_rack.textile1
-rw-r--r--railties/guides/source/routing.textile2
-rw-r--r--railties/lib/rails/application.rb76
-rw-r--r--railties/lib/rails/application/bootstrap.rb21
-rw-r--r--railties/lib/rails/application/configuration.rb47
-rw-r--r--railties/lib/rails/application/finisher.rb56
-rw-r--r--railties/lib/rails/application/routes_reloader.rb19
-rw-r--r--railties/lib/rails/commands/dbconsole.rb2
-rw-r--r--railties/lib/rails/engine.rb4
-rw-r--r--railties/lib/rails/engine/configuration.rb2
-rw-r--r--railties/lib/rails/generators/app_base.rb37
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt10
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/gitignore3
-rw-r--r--railties/lib/rails/railtie/configuration.rb12
-rw-r--r--railties/lib/rails/source_annotation_extractor.rb16
-rw-r--r--railties/test/application/assets_test.rb23
-rw-r--r--railties/test/application/console_test.rb1
-rw-r--r--railties/test/application/initializers/frameworks_test.rb7
-rw-r--r--railties/test/application/initializers/i18n_test.rb3
-rw-r--r--railties/test/application/loading_test.rb163
-rw-r--r--railties/test/application/middleware/cache_test.rb4
-rw-r--r--railties/test/application/middleware/exceptions_test.rb30
-rw-r--r--railties/test/application/rake/migrations_test.rb109
-rw-r--r--railties/test/application/rake/notes_test.rb45
-rw-r--r--railties/test/application/rake_test.rb68
-rw-r--r--railties/test/generators/actions_test.rb6
-rw-r--r--railties/test/generators/app_generator_test.rb41
-rw-r--r--railties/test/railties/shared_tests.rb14
50 files changed, 1185 insertions, 366 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index d158fdd46f..0bd76df6d7 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,5 +1,11 @@
## Rails 3.2.0 (unreleased) ##
+* Added `config.exceptions_app` to set the exceptions application invoked by the ShowException middleware when an exception happens. Defaults to `ActionDispatch::PublicExceptions.new(Rails.public_path)`. *José Valim*
+
+* Speed up development by only reloading classes if dependencies files changed. This can be turned off by setting `config.reload_classes_only_on_change` to false. *José Valim*
+
+* New applications get a flag `config.active_record.auto_explain_threshold_in_seconds` in the environments configuration files. With a value of 0.5 in development.rb, and commented out in production.rb. No mention in test.rb. *fxn*
+
* Add DebugExceptions middleware which contains features extracted from ShowExceptions middleware *José Valim*
* Display mounted engine's routes in `rake routes` *Piotr Sarnacki*
diff --git a/railties/guides/code/getting_started/README b/railties/guides/code/getting_started/README.rdoc
index 7c36f2356e..7c36f2356e 100644
--- a/railties/guides/code/getting_started/README
+++ b/railties/guides/code/getting_started/README.rdoc
diff --git a/railties/guides/code/getting_started/config/environments/development.rb b/railties/guides/code/getting_started/config/environments/development.rb
index 89932bf19b..d60a10568b 100644
--- a/railties/guides/code/getting_started/config/environments/development.rb
+++ b/railties/guides/code/getting_started/config/environments/development.rb
@@ -22,6 +22,13 @@ Blog::Application.configure do
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
+ # Raise exception on mass assignment protection for ActiveRecord models
+ config.active_record.mass_assignment_sanitizer = :strict
+
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ config.active_record.auto_explain_threshold_in_seconds = 0.5
+
# Do not compress assets
config.assets.compress = false
diff --git a/railties/guides/code/getting_started/config/environments/production.rb b/railties/guides/code/getting_started/config/environments/production.rb
index dee8acfdfe..c9b2f41c39 100644
--- a/railties/guides/code/getting_started/config/environments/production.rb
+++ b/railties/guides/code/getting_started/config/environments/production.rb
@@ -60,4 +60,8 @@ Blog::Application.configure do
# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify
+
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ # config.active_record.auto_explain_threshold_in_seconds = 0.5
end
diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile
index b34c223b31..bc85f07ecc 100644
--- a/railties/guides/source/action_controller_overview.textile
+++ b/railties/guides/source/action_controller_overview.textile
@@ -16,7 +16,7 @@ h3. What Does a Controller Do?
Action Controller is the C in MVC. After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output. Luckily, Action Controller does most of the groundwork for you and uses smart conventions to make this as straightforward as possible.
-For most conventional RESTful applications, the controller will receive the request (this is invisible to you as the developer), fetch or save data from a model and use a view to create HTML output. If your controller needs to do things a little differently, that's not a problem, this is just the most common way for a controller to work.
+For most conventional "RESTful":http://en.wikipedia.org/wiki/Representational_state_transfer applications, the controller will receive the request (this is invisible to you as the developer), fetch or save data from a model and use a view to create HTML output. If your controller needs to do things a little differently, that's not a problem, this is just the most common way for a controller to work.
A controller can thus be thought of as a middle man between models and views. It makes the model data available to the view so it can display that data to the user, and it saves or updates data from the user to the model.
diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile
index 352f23dc01..0cbabd71a1 100644
--- a/railties/guides/source/active_record_querying.textile
+++ b/railties/guides/source/active_record_querying.textile
@@ -1369,6 +1369,42 @@ EXPLAIN for: SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1)
under MySQL.
+h4. Automatic EXPLAIN
+
+Active Record is able to run EXPLAIN automatically on slow queries and log its
+output. This feature is controlled by the configuration parameter
+
+<ruby>
+config.active_record.auto_explain_threshold_in_seconds
+</ruby>
+
+If set to a number, any query exceeding those many seconds will have its EXPLAIN
+automatically triggered and logged. In the case of relations, the threshold is
+compared to the total time needed to fetch records. So, a relation is seen as a
+unit of work, no matter whether the implementation of eager loading involves
+several queries under the hood.
+
+A threshold of +nil+ disables automatic EXPLAINs.
+
+The default threshold in development mode is 0.5 seconds, and +nil+ in test and
+production modes.
+
+h5. Disabling Automatic EXPLAIN
+
+Automatic EXPLAIN can be selectively silenced with +ActiveRecord::Base.silence_auto_explain+:
+
+<ruby>
+ActiveRecord::Base.silence_auto_explain do
+ # no automatic EXPLAIN is triggered here
+end
+</ruby>
+
+That may be useful for queries you know are slow but fine, like a heavyweight
+report of an admin interface.
+
+As its name suggests, +silence_auto_explain+ only silences automatic EXPLAINs.
+Explicit calls to +ActiveRecord::Relation#explain+ run.
+
h4. Interpreting EXPLAIN
Interpretation of the output of EXPLAIN is beyond the scope of this guide. The
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 7959a88c5b..6646e9cd05 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -1301,7 +1301,7 @@ NOTE: Defined in +active_support/core_ext/string/output_safety.rb+.
h5. Transformation
-As a rule of thumb, except perhaps for concatenation as explained above, any method that may change a string gives you an unsafe string. These are +donwcase+, +gsub+, +strip+, +chomp+, +underscore+, etc.
+As a rule of thumb, except perhaps for concatenation as explained above, any method that may change a string gives you an unsafe string. These are +downcase+, +gsub+, +strip+, +chomp+, +underscore+, etc.
In the case of in-place transformations like +gsub!+ the receiver itself becomes unsafe.
@@ -2053,6 +2053,16 @@ end
NOTE: Defined in +active_support/core_ext/enumerable.rb+.
+h4. +pluck+
+
+The +pluck+ method collects the value of the passed method for each element and returns the result as an array.
+
+<ruby>
+people.pluck(:name) # => [ "David Heinemeier Hansson", "Jamie Heinemeier Hansson" ]
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/enumerable.rb+.
+
h4. +each_with_object+
The +inject+ method offers iteration with an accumulator:
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index 3681501293..f48f5afd54 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -369,10 +369,10 @@ It is important that this folder is shared between deployments so that remotely
NOTE. If you are precompiling your assets locally, you can use +bundle install --without assets+ on the server to avoid installing the assets gems (the gems in the assets group in the Gemfile).
-The default matcher for compiling files includes +application.js+, +application.css+ and all files that do not end in +js+ or +css+:
+The default matcher for compiling files includes +application.js+, +application.css+ and all non-JS/CSS files (ie. +.coffee+ and +.scss+ files are *not* automatically included as they compile to JS/CSS):
<ruby>
-[ /\w<plus>\.(?!js|css).<plus>/, /application.(css|js)$/ ]
+[ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) }, /application.(css|js)$/ ]
</ruby>
If you have other manifests or individual stylesheets and JavaScript files to include, you can add them to the +precompile+ array:
@@ -410,10 +410,6 @@ For Apache:
<plain>
<LocationMatch "^/assets/.*$">
- # Some browsers still send conditional-GET requests if there's a
- # Last-Modified header or an ETag header even if they haven't
- # reached the expiry date sent in the Expires header.
- Header unset Last-Modified
Header unset ETag
FileETag None
# RFC says only cache for 1 year
@@ -429,10 +425,6 @@ location ~ ^/assets/ {
expires 1y;
add_header Cache-Control public;
- # Some browsers still send conditional-GET requests if there's a
- # Last-Modified header or an ETag header even if they haven't
- # reached the expiry date sent in the Expires header.
- add_header Last-Modified "";
add_header ETag "";
break;
}
@@ -577,7 +569,7 @@ TODO: Registering gems on "Tilt":https://github.com/rtomayko/tilt enabling Sproc
h3. Upgrading from Old Versions of Rails
-There are two issues when upgrading. The first is moving the files to the new locations. See the section above for guidance on the correct locations for different file types.
+There are two issues when upgrading. The first is moving the files to the new locations. See "Asset Organization":#asset-organization above for guidance on the correct locations for different file types.
The second is updating the various environment files with the correct default options. The following changes reflect the defaults in version 3.1.0.
diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile
index 0ef6f51190..ec9bfd4d40 100644
--- a/railties/guides/source/caching_with_rails.textile
+++ b/railties/guides/source/caching_with_rails.textile
@@ -332,6 +332,14 @@ caches_action :index, :expires_in => 60.seconds, :unless_exist => true
For more information about Ehcache, see "http://ehcache.org/":http://ehcache.org/ .
For more information about Ehcache for JRuby and Rails, see "http://ehcache.org/documentation/jruby.html":http://ehcache.org/documentation/jruby.html
+h4. ActiveSupport::Cache::NullStore
+
+This cache store implementation is meant to be used only in development or test environments and it never stores anything. This can be very useful in development when you have code that interacts directly with +Rails.cache+, but caching may interfere with being able to see the results of code changes. With this cache store, all +fetch+ and +read+ operations will result in a miss.
+
+<ruby>
+ActionController::Base.cache_store = :null
+</ruby>
+
h4. Custom Cache Stores
You can create your own custom cache store by simply extending +ActiveSupport::Cache::Store+ and implementing the appropriate methods. In this way, you can swap in any number of caching technologies into your Rails application.
diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile
index 9284a542f3..58855bc80b 100644
--- a/railties/guides/source/command_line.textile
+++ b/railties/guides/source/command_line.textile
@@ -36,7 +36,7 @@ WARNING: You can install the rails gem by typing +gem install rails+, if you don
<shell>
$ rails new commandsapp
create
- create README
+ create README.rdoc
create .gitignore
create Rakefile
create config.ru
@@ -391,7 +391,7 @@ 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
+Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, 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
@@ -420,7 +420,7 @@ The +doc:+ namespace has the tools to generate documentation for your app, API d
h4. +notes+
-+rake notes+ will search through your code for comments beginning with FIXME, OPTIMIZE or TODO. The search is only done in files with extension +.builder+, +.rb+, +.rxml+, +.rhtml+ and +.erb+ for both default and custom annotations.
++rake notes+ will search through your code for comments beginning with FIXME, OPTIMIZE or TODO. The search is done in files with extension +.builder+, +.rb+, +.erb+, +.haml+ and +.slim+ for both default and custom annotations.
<shell>
$ rake notes
@@ -509,8 +509,8 @@ $ rails new . --git --database=postgresql
create tmp/pids
create Rakefile
add 'Rakefile'
- create README
-add 'README'
+ create README.rdoc
+add 'README.rdoc'
create app/controllers/application_controller.rb
add 'app/controllers/application_controller.rb'
create app/helpers/application_helper.rb
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index d91011c370..09ef308665 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -82,6 +82,10 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is
* +config.encoding+ sets up the application-wide encoding. Defaults to UTF-8.
+* +config.exceptions_app+ sets the exceptions application invoked by the ShowException middleware when an exception happens. Defaults to +ActionDispatch::PublicExceptions.new(Rails.public_path)+.
+
+* +config.file_watcher+ the class used to detect file updates in the filesystem when +config.reload_classes_only_on_change+ is true. Must conform to +ActiveSupport::FileUpdateChecker+ API.
+
* +config.filter_parameters+ used for filtering out the parameters that you don't want shown in the logs, such as passwords or credit card numbers.
* +config.force_ssl+ forces all requests to be under HTTPS protocol by using +Rack::SSL+ middleware.
@@ -98,6 +102,8 @@ NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is
* +config.preload_frameworks+ enables or disables preloading all frameworks at startup. Enabled by +config.threadsafe!+. Defaults to +nil+, so is disabled.
+* +config.reload_classes_only_on_change+ enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If +config.cache_classes+ is true, this option is ignored.
+
* +config.reload_plugins+ enables or disables plugin reloading. Defaults to false.
* +config.secret_token+ used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get +config.secret_token+ initialized to a random key in +config/initializers/secret_token.rb+.
@@ -268,6 +274,8 @@ h4. Configuring Active Record
* +config.active_record.identity_map+ controls whether the identity map is enabled, and is false by default.
+* +config.active_record.auto_explain_threshold_in_seconds+ configures the threshold for automatic EXPLAINs (+nil+ disables this feature). Queries exceeding the threshold get their query plan logged. Default is 0.5 in development mode.
+
The MySQL adapter adds one additional configuration option:
* +ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans+ controls whether Active Record will consider all +tinyint(1)+ columns in a MySQL database to be booleans and is true by default.
diff --git a/railties/guides/source/contributing_to_ruby_on_rails.textile b/railties/guides/source/contributing_to_ruby_on_rails.textile
index 37ead2bff2..92cb0774de 100644
--- a/railties/guides/source/contributing_to_ruby_on_rails.textile
+++ b/railties/guides/source/contributing_to_ruby_on_rails.textile
@@ -336,7 +336,7 @@ It’s pretty likely that other changes to master have happened while you were w
<shell>
$ git checkout master
-$ git pull
+$ git pull --rebase
</shell>
Now reapply your patch on top of the latest changes:
diff --git a/railties/guides/source/debugging_rails_applications.textile b/railties/guides/source/debugging_rails_applications.textile
index 3552c68418..57c7786636 100644
--- a/railties/guides/source/debugging_rails_applications.textile
+++ b/railties/guides/source/debugging_rails_applications.textile
@@ -465,7 +465,7 @@ Now you should know where you are in the running trace and be able to print the
Use +step+ (abbreviated +s+) to continue running your program until the next logical stopping point and return control to ruby-debug.
-TIP: You can also use +step+ _n_+ and +step- _n_+ to move forward or backward _n_ steps respectively.
+TIP: You can also use <tt>step<plus> n</tt> and <tt>step- n</tt> to move forward or backward +n+ steps respectively.
You may also use +next+ which is similar to step, but function or method calls that appear within the line of code are executed without stopping. As with step, you may use plus sign to move _n_ steps.
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index fe43c9db36..774c6a792e 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -289,7 +289,7 @@ rundown on the function of each of the files and folders that Rails created by d
|log/|Application log files.|
|public/|The only folder seen to the world as-is. Contains the static files and compiled assets.|
|Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.|
-|README|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.|
+|README.rdoc|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.|
|script/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.|
|test/|Unit tests, fixtures, and other test apparatus. These are covered in "Testing Rails Applications":testing.html|
|tmp/|Temporary files|
diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile
index e9477e84cf..16ad35f345 100644
--- a/railties/guides/source/i18n.textile
+++ b/railties/guides/source/i18n.textile
@@ -825,7 +825,7 @@ h5. Active Record Methods
* +ActiveRecord::Errors#generate_message+ (which is used by Active Record validations but may also be used manually) uses +model_name.human+ and +human_attribute_name+ (see above). It also translates the error message and supports translations for inherited class names as explained above in "Error message scopes".
-*+ ActiveRecord::Errors#full_messages+ prepends the attribute name to the error message using a separator that will be looked up from "activerecord.errors.format.separator":https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L91 (and which defaults to +'&nbsp;'+).
+* +ActiveRecord::Errors#full_messages+ prepends the attribute name to the error message using a separator that will be looked up from "activerecord.errors.format.separator":https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L91 (and which defaults to +'&nbsp;'+).
h5. Active Support Methods
diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile
index df7b9b364c..5cff2d0893 100644
--- a/railties/guides/source/layouts_and_rendering.textile
+++ b/railties/guides/source/layouts_and_rendering.textile
@@ -495,7 +495,7 @@ def show
end
</ruby>
-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.
+Make sure to use +and return+ instead of +&amp;&amp; return+ because +&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, so the following will work without errors:
@@ -671,19 +671,33 @@ There are three tag options available for the +auto_discovery_link_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+:
+The +javascript_include_tag+ helper returns an HTML +script+ tag for each source provided.
+
+If you are using Rails with the "Asset Pipeline":asset_pipeline.html enabled, this helper will generate a link to +/assets/javascripts/+ rather than +public/javascripts+ which was used in earlier versions of Rails. This link is then served by the Sprockets gem, which was introduced in Rails 3.1.
+
+A JavaScript file within a Rails application or Rails engine goes in one of three locations: +app/assets+, +lib/assets+ or +vendor/assets+. These locations are explained in detail in the "Asset Organization section in the Asset Pipeline Guide":asset_pipeline.html#asset-organization
+
+You can specify a full path relative to the document root, or a URL, if you prefer. For example, to link to a JavaScript file that is inside a directory called +javascripts+ inside of one of +app/assets+, +lib/assets+ or +vendor/assets+, you would do this:
<erb>
<%= javascript_include_tag "main" %>
</erb>
-To include +public/javascripts/main.js+ and +public/javascripts/columns.js+:
+Rails will then output a +script+ tag such as this:
+
+<html>
+<script src='/assets/main.js' type="text/javascript"></script>
+</html>
+
+The request to this asset is then served by the Sprockets gem.
+
+To include multiple files such as +app/assets/javascripts/main.js+ and +app/assets/javascripts/columns.js+ at the same time:
<erb>
<%= javascript_include_tag "main", "columns" %>
</erb>
-To include +public/javascripts/main.js+ and +public/photos/columns.js+:
+To include +app/assets/javascripts/main.js+ and +app/assets/javascripts/photos/columns.js+:
<erb>
<%= javascript_include_tag "main", "/photos/columns" %>
@@ -701,15 +715,38 @@ If the application does not use the asset pipeline, the +:defaults+ option loads
<%= javascript_include_tag :defaults %>
</erb>
-And you can in any case override the expansion in <tt>config/application.rb</tt>:
+Outputting +script+ tags such as this:
+
+<html>
+<script src="/javascripts/jquery.js" type="text/javascript"></script>
+<script src="/javascripts/jquery_ujs.js" type="text/javascript"></script>
+</html>
+
+These two files for jQuery, +jquery.js+ and +jquery_ujs.js+ must be placed inside +public/javascripts+ if the application doesn't use the asset pipeline. These files can be downloaded from the "jquery-rails repository on GitHub":https://github.com/indirect/jquery-rails/tree/master/vendor/assets/javascripts
+
+WARNING: If you are using the asset pipeline, this tag will render a +script+ tag for an asset called +defaults.js+, which would not exist in your application unless you've explicitly defined it to be.
+
+And you can in any case override the +:defaults+ expansion in <tt>config/application.rb</tt>:
<ruby>
config.action_view.javascript_expansions[:defaults] = %w(foo.js bar.js)
</ruby>
-When using <tt>:defaults</tt>, if an <tt>application.js</tt> file exists in <tt>public/javascripts</tt> it will be included as well at then end.
+You can also define new defaults:
+
+<ruby>
+config.action_view.javascript_expansions[:projects] = %w(projects.js tickets.js)
+</ruby>
+
+And use them by referencing them exactly like +:defaults+:
-Also, the +:all+ option loads every JavaScript file in +public/javascripts+:
+<erb>
+<%= javascript_include_tag :projects %>
+</erb>
+
+When using <tt>:defaults</tt>, if an <tt>application.js</tt> file exists in <tt>public/javascripts</tt> it will be included as well at the end.
+
+Also, if the asset pipeline is disabled, the +:all+ expansion loads every JavaScript file in +public/javascripts+:
<erb>
<%= javascript_include_tag :all %>
@@ -740,19 +777,23 @@ You can even use dynamic paths such as +cache/#{current_site}/main/display+.
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+:
+The +stylesheet_link_tag+ helper returns an HTML +&lt;link&gt;+ tag for each source provided.
+
+If you are using Rails with the "Asset Pipeline" enabled, this helper will generate a link to +/assets/stylesheets/+. This link is then processed by the Sprockets gem. A stylesheet file can be stored in one of three locations: +app/assets+, +lib/assets+ or +vendor/assets+.
+
+You can specify a full path relative to the document root, or a URL. For example, to link to a stylesheet file that is inside a directory called +stylesheets+ inside of one of +app/assets+, +lib/assets+ or +vendor/assets+, you would do this:
<erb>
<%= stylesheet_link_tag "main" %>
</erb>
-To include +public/stylesheets/main.css+ and +public/stylesheets/columns.css+:
+To include +app/assets/stylesheets/main.css+ and +app/assets/stylesheets/columns.css+:
<erb>
<%= stylesheet_link_tag "main", "columns" %>
</erb>
-To include +public/stylesheets/main.css+ and +public/photos/columns.css+:
+To include +app/assets/stylesheets/main.css+ and +app/assets/stylesheets/photos/columns.css+:
<erb>
<%= stylesheet_link_tag "main", "/photos/columns" %>
@@ -770,7 +811,7 @@ By default, the +stylesheet_link_tag+ creates links with +media="screen" rel="st
<%= stylesheet_link_tag "main_print", :media => "print" %>
</erb>
-The +all+ option links every CSS file in +public/stylesheets+:
+If the asset pipeline is disabled, the +all+ option links every CSS file in +public/stylesheets+:
<erb>
<%= stylesheet_link_tag :all %>
diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile
index c63f2aa119..92356edf90 100644
--- a/railties/guides/source/migrations.textile
+++ b/railties/guides/source/migrations.textile
@@ -1,12 +1,24 @@
h2. Migrations
-Migrations are a convenient way for you to alter your database in a structured and organized manner. You could edit fragments of SQL by hand but you would then be responsible for telling other developers that they need to go and run them. You'd also have to keep track of which changes need to be run against the production machines next time you deploy.
-
-Active Record tracks which migrations have already been run so all you have to do is update your source and run +rake db:migrate+. Active Record will work out which migrations should be run. It will also update your +db/schema.rb+ file to match the structure of your database.
-
-Migrations also allow you to describe these transformations using Ruby. The great thing about this is that (like most of Active Record's functionality) it is database independent: you don't need to worry about the precise syntax of +CREATE TABLE+ any more than you worry about variations on +SELECT *+ (you can drop down to raw SQL for database specific features). For example you could use SQLite3 in development, but MySQL in production.
-
-You'll learn all about migrations including:
+Migrations are a convenient way for you to alter your database in a structured
+and organized manner. You could edit fragments of SQL by hand but you would then
+be responsible for telling other developers that they need to go and run them.
+You'd also have to keep track of which changes need to be run against the
+production machines next time you deploy.
+
+Active Record tracks which migrations have already been run so all you have to
+do is update your source and run +rake db:migrate+. Active Record will work out
+which migrations should be run. It will also update your +db/schema.rb+ file to
+match the structure of your database.
+
+Migrations also allow you to describe these transformations using Ruby. The
+great thing about this is that (like most of Active Record's functionality) it
+is database independent: you don't need to worry about the precise syntax of
++CREATE TABLE+ any more than you worry about variations on +SELECT *+ (you can
+drop down to raw SQL for database specific features). For example you could use
+SQLite3 in development, but MySQL in production.
+
+In this guide, you'll learn all about migrations including:
* The generators you can use to create them
* The methods Active Record provides to manipulate your database
@@ -17,7 +29,8 @@ endprologue.
h3. Anatomy of a Migration
-Before we dive into the details of a migration, here are a few examples of the sorts of things you can do:
+Before we dive into the details of a migration, here are a few examples of the
+sorts of things you can do:
<ruby>
class CreateProducts < ActiveRecord::Migration
@@ -36,9 +49,15 @@ class CreateProducts < ActiveRecord::Migration
end
</ruby>
-This migration adds a table called +products+ with a string column called +name+ and a text column called +description+. A primary key column called +id+ will also be added, however since this is the default we do not need to ask for this. The timestamp columns +created_at+ and +updated_at+ which Active Record populates automatically will also be added. Reversing this migration is as simple as dropping the table.
+This migration adds a table called +products+ with a string column called +name+
+and a text column called +description+. A primary key column called +id+ will
+also be added, however since this is the default we do not need to ask for this.
+The timestamp columns +created_at+ and +updated_at+ which Active Record
+populates automatically will also be added. Reversing this migration is as
+simple as dropping the table.
-Migrations are not limited to changing the schema. You can also use them to fix bad data in the database or populate new fields:
+Migrations are not limited to changing the schema. You can also use them to fix
+bad data in the database or populate new fields:
<ruby>
class AddReceiveNewsletterToUsers < ActiveRecord::Migration
@@ -55,12 +74,18 @@ class AddReceiveNewsletterToUsers < ActiveRecord::Migration
end
</ruby>
-NOTE: Some "caveats":#using-models-in-your-migrations apply to using models in your migrations.
+NOTE: Some "caveats":#using-models-in-your-migrations apply to using models in
+your migrations.
-This migration adds a +receive_newsletter+ column to the +users+ table. We want it to default to +false+ for new users, but existing users are considered
-to have already opted in, so we use the User model to set the flag to +true+ for existing users.
+This migration adds a +receive_newsletter+ column to the +users+ table. We want
+it to default to +false+ for new users, but existing users are considered to
+have already opted in, so we use the User model to set the flag to +true+ for
+existing users.
-Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method. This method is preferred for writing constructive migrations (adding columns or tables). The migration knows how to migrate your database and reverse it when the migration is rolled back without the need to write a separate +down+ method.
+Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method.
+This method is preferred for writing constructive migrations (adding columns or
+tables). The migration knows how to migrate your database and reverse it when
+the migration is rolled back without the need to write a separate +down+ method.
<ruby>
class CreateProducts < ActiveRecord::Migration
@@ -77,64 +102,111 @@ end
h4. Migrations are Classes
-A migration is a subclass of <tt>ActiveRecord::Migration</tt> that implements two methods: +up+ (perform the required transformations) and +down+ (revert them).
+A migration is a subclass of <tt>ActiveRecord::Migration</tt> that implements
+two methods: +up+ (perform the required transformations) and +down+ (revert
+them).
-Active Record provides methods that perform common data definition tasks in a database independent way (you'll read about them in detail later):
+Active Record provides methods that perform common data definition tasks in a
+database independent way (you'll read about them in detail later):
-* +create_table+
-* +change_table+
-* +drop_table+
* +add_column+
+* +add_index+
* +change_column+
-* +rename_column+
+* +change_table+
+* +create_table+
+* +drop_table+
* +remove_column+
-* +add_index+
* +remove_index+
+* +rename_column+
-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).
+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.
+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 rollback
+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 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+.
+Migrations are stored as files in the +db/migrate+ directory, 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+.
<ruby>
config.active_record.timestamped_migrations = false
</ruby>
-The combination of timestamps and recording which migrations have been run allows Rails to handle common situations that occur with multiple developers.
+The combination of timestamps and recording which migrations have been run
+allows Rails to handle common situations that occur with multiple developers.
-For example Alice adds migrations +20080906120000+ and +20080906123000+ and Bob adds +20080906124500+ and runs it. Alice finishes her changes and checks in her migrations and Bob pulls down the latest changes. Rails knows that it has not run Alice's two migrations so +rake db:migrate+ would run them (even though Bob's migration with a later timestamp has been run), and similarly migrating down would not run their +down+ methods.
+For example Alice adds migrations +20080906120000+ and +20080906123000+ and Bob
+adds +20080906124500+ and runs it. Alice finishes her changes and checks in her
+migrations and Bob pulls down the latest changes. When Bob runs +rake db:migrate+,
+Rails knows that it has not run Alice's two migrations so it executes the +up+ method for each migration.
-Of course this is no substitution for communication within the team. For example, if Alice's migration removed a table that Bob's migration assumed to exist, then trouble would certainly strike.
+Of course this is no substitution for communication within the team. For
+example, if Alice's migration removed a table that Bob's migration assumed to
+exist, then trouble would certainly strike.
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.
+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
-Active Record supports the following types:
+Active Record supports the following database column types:
+* +:binary+
+* +:boolean+
+* +:date+
+* +:datetime+
+* +:decimal+
+* +:float+
+* +:integer+
* +:primary_key+
* +:string+
* +:text+
-* +:integer+
-* +:float+
-* +:decimal+
-* +:datetime+
-* +:timestamp+
* +:time+
-* +:date+
-* +:binary+
-* +:boolean+
+* +:timestamp+
-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
+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 +220,10 @@ 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 these columns 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
@@ -169,12 +244,15 @@ class CreateProducts < ActiveRecord::Migration
end
</ruby>
-You can append as many column name/type pairs as you want. By default +t.timestamps+ (which creates the +updated_at+ and +created_at+ columns that
-are automatically populated by Active Record) will be added for you.
+You can append as many column name/type pairs as you want. By default, the
+generated migration will include +t.timestamps+ (which creates the
++updated_at+ and +created_at+ columns that are automatically populated
+by Active Record).
h4. Creating a Standalone Migration
-If you are creating migrations for other purposes (for example to add a column to an existing table) then you can use the migration generator:
+If you are creating migrations for other purposes (for example to add a column
+to an existing table) then you can also use the migration generator:
<shell>
$ rails generate migration AddPartNumberToProducts
@@ -189,7 +267,9 @@ class AddPartNumberToProducts < ActiveRecord::Migration
end
</ruby>
-If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is followed by a list of column names and types then a migration containing the appropriate +add_column+ and +remove_column+ statements will be created.
+If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is
+followed by a list of column names and types then a migration containing the
+appropriate +add_column+ and +remove_column+ statements will be created.
<shell>
$ rails generate migration AddPartNumberToProducts part_number:string
@@ -242,17 +322,23 @@ class AddDetailsToProducts < ActiveRecord::Migration
end
</ruby>
-As always, what has been generated for you is just a starting point. You can add or remove from it as you see fit.
+As always, what has been generated for you is just a starting point. You can add
+or remove from it as you see fit by editing the
+db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb file.
-NOTE: The generated migration file for destructive migrations will still be old-style using the +up+ and +down+ methods. This is because Rails doesn't know the original data types defined when you made the original changes.
+NOTE: The generated migration file for destructive migrations will still be
+old-style using the +up+ and +down+ methods. This is because Rails needs to know
+the original data types defined when you made the original changes.
h3. Writing a Migration
-Once you have created your migration using one of the generators it's time to get to work!
+Once you have created your migration using one of the generators it's time to
+get to work!
h4. Creating a Table
-Migration method +create_table+ will be one of your workhorses. A typical use would be
+Migration method +create_table+ will be one of your workhorses. A typical use
+would be
<ruby>
create_table :products do |t|
@@ -260,9 +346,11 @@ create_table :products do |t|
end
</ruby>
-which creates a +products+ table with a column called +name+ (and as discussed below, an implicit +id+ column).
+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 it. 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 +358,9 @@ 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 +368,12 @@ 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 the option +: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,11 +381,14 @@ 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
-A close cousin of +create_table+ is +change_table+, used for changing existing tables. It is used in a similar fashion to +create_table+ but the object yielded to the block knows more tricks. For example
+A close cousin of +create_table+ is +change_table+, used for changing existing
+tables. It is used in a similar fashion to +create_table+ but the object yielded
+to the block knows more tricks. For example
<ruby>
change_table :products do |t|
@@ -301,28 +399,23 @@ change_table :products do |t|
end
</ruby>
-removes the +description+ and +name+ columns, creates a +part_number+ column and adds an index on it. Finally it renames the +upccode+ column. This is the same as doing
-
-<ruby>
-remove_column :products, :description
-remove_column :products, :name
-add_column :products, :part_number, :string
-add_index :products, :part_number
-rename_column :products, :upccode, :upc_code
-</ruby>
-
-You don't have to keep repeating the table name and it groups all the statements related to modifying one particular table. The individual transformation names are also shorter, for example +remove_column+ becomes just +remove+ and +add_index+ becomes just +index+.
+removes the +description+ and +name+ columns, creates a +part_number+ string
+column and adds an index on it. Finally it renames the +upccode+ column.
h4. Special Helpers
-Active Record provides some shortcuts for common functionality. It is for example very common to add both the +created_at+ and +updated_at+ columns and so there is a method that does exactly that:
+Active Record provides some shortcuts for common functionality. It is for
+example very common to add both the +created_at+ and +updated_at+ columns and so
+there is a method that does exactly that:
<ruby>
create_table :products do |t|
t.timestamps
end
</ruby>
-will create a new products table with those two columns (plus the +id+ column) whereas
+
+will create a new products table with those two columns (plus the +id+ column)
+whereas
<ruby>
change_table :products do |t|
@@ -331,7 +424,8 @@ end
</ruby>
adds those columns to an existing table.
-The other helper is called +references+ (also available as +belongs_to+). In its simplest form it just adds some readability
+Another helper is called +references+ (also available as +belongs_to+). In its
+simplest form it just adds some readability.
<ruby>
create_table :products do |t|
@@ -339,24 +433,42 @@ create_table :products do |t|
end
</ruby>
-will create a +category_id+ column of the appropriate type. Note that you pass the model name, not the column name. Active Record adds the +_id+ for you. If you have polymorphic +belongs_to+ associations then +references+ will add both of the columns required:
+will create a +category_id+ column of the appropriate type. Note that you pass
+the model name, not the column name. Active Record adds the +_id+ for you. If
+you have polymorphic +belongs_to+ associations then +references+ will add both
+of the columns required:
<ruby>
create_table :products do |t|
t.references :attachment, :polymorphic => {:default => 'Photo'}
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+ or a plugin that adds "foreign key support":#active-record-and-referential-integrity.
+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+ 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+ method 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
+h4. Using the +change+ Method
-The +change+ method removes the need to write both +up+ and +down+ methods in those cases that Rails know how to revert the changes automatically. Currently, the +change+ method supports only these migration definitions:
+The +change+ method removes the need to write both +up+ and +down+ methods in
+those cases that Rails know how to revert the changes automatically. Currently,
+the +change+ method supports only these migration definitions:
* +add_column+
* +add_index+
@@ -367,15 +479,20 @@ The +change+ method removes the need to write both +up+ and +down+ methods in th
* +rename_index+
* +rename_table+
-If you're going to use other methods, you'll have to write the +up+ and +down+ methods normally.
+If you're going to need to use any other methods, you'll have to write the
++up+ and +down+ methods instead of using the +change+ method.
-h4. Writing Your +down+ Method
+h4. Using the +up+/+down+ Methods
-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,
+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
-
def up
create_table :products do |t|
t.references :category
@@ -387,47 +504,69 @@ class ExampleMigration < ActiveRecord::Migration
FOREIGN KEY (category_id)
REFERENCES categories(id)
SQL
-
add_column :users, :home_page_url, :string
-
rename_column :users, :email, :email_address
end
def down
rename_column :users, :email_address, :email
remove_column :users, :home_page_url
- execute "ALTER TABLE products DROP FOREIGN KEY fk_products_categories"
+ execute <<-SQL
+ ALTER TABLE products
+ DROP FOREIGN KEY fk_products_categories
+ SQL
drop_table :products
end
end
</ruby>
-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.
+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 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.
+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
++rake db:migrate+. In its most basic form it just runs the +up+ or +change+
+method for all the migrations that have not yet been run. If there are
+no such migrations, it exits. It will run these migrations in order based
+on the date of the migration.
-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.
+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
+If you specify a target version, Active Record will run the required migrations
+(up, down or change) 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
<shell>
$ rake db:migrate VERSION=20080906120000
</shell>
-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.
+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, and will not execute any later migrations. If
+migrating downwards, this will run the +down+ method on all the migrations
+down to, but not including, 20080906120000.
h4. Rolling Back
-A common task is to rollback the last migration, for example if you made a mistake in it and wish to correct it. Rather than tracking down the version number associated with the previous migration you can run
+A common task is to rollback the last migration, for example if you made a
+mistake in it and wish to correct it. Rather than tracking down the version
+number associated with the previous migration you can run
<shell>
$ rake db:rollback
</shell>
-This will run the +down+ method from the latest migration. If you need to undo several migrations you can provide a +STEP+ parameter:
+This will run the +down+ method from the latest migration. If you need to undo
+several migrations you can provide a +STEP+ parameter:
<shell>
$ rake db:rollback STEP=3
@@ -435,46 +574,65 @@ $ 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.
+h4. Resetting the database
-NOTE: This is not the same as running all the migrations - see the section on "schema.rb":#schema-dumping-and-you.
+The +rake db:reset+ task will drop the database, recreate it and load the
+current schema into it.
-h4. Being Specific
+NOTE: This is not the same as running all the migrations - see the section on
+"schema.rb":#schema-dumping-and-you.
-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,
+h4. Running specific migrations
+
+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
</shell>
-will run the +up+ method from the 20080906120000 migration. These tasks check whether the migration has already run, so for example +db:migrate:up VERSION=20080906120000+ will do nothing if Active Record believes that 20080906120000 has already been run.
+will run the +up+ method from the 20080906120000 migration. These tasks still
+check whether the migration has already run, so for example +db:migrate:up
+VERSION=20080906120000+ will do nothing if Active Record believes that
+20080906120000 has already been run.
-h4. Being Talkative
+h4. Changing the output of running migrations
-By default migrations tell you exactly what they're doing and how long it took. A migration creating a table and adding an index might produce output like this
+By default migrations tell you exactly what they're doing and how long it took.
+A migration creating a table and adding an index might produce output like this
<shell>
-20080906170109 CreateProducts: migrating
+== CreateProducts: migrating =================================================
-- create_table(:products)
- -> 0.0021s
--- add_index(:products, :name)
- -> 0.0026s
-20080906170109 CreateProducts: migrated (0.0059s)
+ -> 0.0028s
+== CreateProducts: migrated (0.0028s) ========================================
</shell>
-Several methods are provided that allow you to control all this:
+Several methods are provided in migrations that allow you to control all this:
-* +suppress_messages+ takes a block as an argument and suppresses any output generated by the block.
-* +say+ takes a message argument and outputs it as is. A second boolean argument can be passed to specify whether to indent or not.
-* +say_with_time+ outputs text along with how long it took to run its block. If the block returns an integer it assumes it is the number of rows affected.
+|_.Method |_.Purpose|
+|suppress_messages |Takes a block as an argument and suppresses any output
+ generated by the block.|
+|say |Takes a message argument and outputs it as is. A second
+ boolean argument can be passed to specify whether to
+ indent or not.|
+|say_with_time |Outputs text along with how long it took to run its
+ block. If the block returns an integer it assumes it
+ is the number of rows affected.|
For example, this migration
@@ -502,37 +660,46 @@ end
generates the following output
<shell>
-20080906170109 CreateProducts: migrating
- Created a table
+== CreateProducts: migrating =================================================
+-- Created a table
-> and an index!
- Waiting for a while
- -> 10.0001s
+-- Waiting for a while
+ -> 10.0013s
-> 250 rows
-20080906170109 CreateProducts: migrated (10.0097s)
+== CreateProducts: migrated (10.0054s) =======================================
</shell>
-If you just want Active Record to shut up, then running +rake db:migrate VERBOSE=false+ will suppress all output.
+If you want Active Record to not output anything, 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.
+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.
-Consider this example, where Alice and Bob are working on the same code base which contains a +Product+ model:
+Consider this example, where Alice and Bob are working on the same code base
+which contains a +Product+ model:
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.
+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.
<ruby>
# db/migrate/20100513121110_add_flag_to_product.rb
class AddFlagToProduct < ActiveRecord::Migration
def change
- add_column :products, :flag, :int
- Product.all.each { |f| f.update_attributes!(:flag => 'false') }
+ add_column :products, :flag, :boolean
+ Product.all.each do |product|
+ product.update_attributes!(:flag => 'false')
+ end
end
end
</ruby>
@@ -545,7 +712,9 @@ 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
@@ -553,7 +722,9 @@ Alice adds a second migration which adds and initializes another column to the +
class AddFuzzToProduct < ActiveRecord::Migration
def change
add_column :products, :fuzz, :string
- Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
+ Product.all.each do |product|
+ product.update_attributes! :fuzz => 'fuzzy'
+ end
end
end
</ruby>
@@ -570,10 +741,14 @@ Both migrations work for Alice.
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.
+# 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!
@@ -582,9 +757,12 @@ An error has occurred, this and all later migrations canceled:
undefined method `fuzz' for #<Product:0x000001049b14a0>
</plain>
-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.
+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:
@@ -596,9 +774,11 @@ class AddFlagToProduct < ActiveRecord::Migration
end
def change
- add_column :products, :flag, :int
+ add_column :products, :flag, :integer
Product.reset_column_information
- Product.all.each { |f| f.update_attributes!(:flag => false) }
+ Product.all.each do |product|
+ product.update_attributes!(:flag => false)
+ end
end
end
</ruby>
@@ -609,32 +789,50 @@ end
class AddFuzzToProduct < ActiveRecord::Migration
class Product < ActiveRecord::Base
end
+
def change
add_column :products, :fuzz, :string
Product.reset_column_information
- Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
+ Product.all.each do |product|
+ product.update_attributes!(:fuzz => 'fuzzy')
+ end
end
end
</ruby>
-
h3. Schema Dumping and You
h4. What are Schema Files for?
-Migrations, mighty as they may be, are not the authoritative source for your database schema. That role falls to either +db/schema.rb+ or an SQL file which Active Record generates by examining the database. They are not designed to be edited, they just represent the current state of the database.
+Migrations, mighty as they may be, are not the authoritative source for your
+database schema. That role falls to either +db/schema.rb+ or an SQL file which
+Active Record generates by examining the database. They are not designed to be
+edited, they just represent the current state of the database.
-There is no need (and it is error prone) to deploy a new instance of an app by replaying the entire migration history. It is much simpler and faster to just load into the database a description of the current schema.
+There is no need (and it is error prone) to deploy a new instance of an app by
+replaying the entire migration history. It is much simpler and faster to just
+load into the database a description of the current schema.
-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.
+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 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.
+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 the information is nicely
+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
-There are two ways to dump the schema. This is set in +config/application.rb+ by the +config.active_record.schema_format+ setting, which may be either +:sql+ or +:ruby+.
+There are two ways to dump the schema. This is set in +config/application.rb+ by
+the +config.active_record.schema_format+ setting, which may be either +:sql+ or
++:ruby+.
-If +:ruby+ is selected then the schema is stored in +db/schema.rb+. If you look at this file you'll find that it looks an awful lot like one very big migration:
+If +:ruby+ is selected then the schema is stored in +db/schema.rb+. If you look
+at this file you'll find that it looks an awful lot like one very big migration:
<ruby>
ActiveRecord::Schema.define(:version => 20080906171750) do
@@ -646,28 +844,57 @@ ActiveRecord::Schema.define(:version => 20080906171750) do
create_table "products", :force => true do |t|
t.string "name"
- t.text "description"
+ t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
- t.string "part_number"
+ t.string "part_number"
end
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.
-
-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 the database (via the +db:structure:dump+ Rake task) into +db/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.
+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+.
+
+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/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
-Because schema dumps are the authoritative source for your database schema, it is strongly recommended that you check them into source control.
+Because schema dumps are the authoritative source for your database schema, it
+is strongly recommended that you check them into source control.
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.
-
-Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. You could also use some plugin like "foreigner":https://github.com/matthuhiggins/foreigner which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+).
+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 in the database.
+
+Although Active Record does not provide any tools for working directly with such
+features, the +execute+ method can be used to execute arbitrary SQL. You could
+also use some plugin like "foreigner":https://github.com/matthuhiggins/foreigner
+which add foreign key support to Active Record (including support for dumping
+foreign keys in +db/schema.rb+).
diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile
index 2440927542..958b13cd9e 100644
--- a/railties/guides/source/performance_testing.textile
+++ b/railties/guides/source/performance_testing.textile
@@ -151,7 +151,7 @@ Performance tests can be run in two modes: Benchmarking and Profiling.
h5. Benchmarking
-Benchmarking makes it easy to quickly gather a few metrics about each test tun. By default, each test case is run *4 times* in benchmarking mode.
+Benchmarking makes it easy to quickly gather a few metrics about each test run. By default, each test case is run *4 times* in benchmarking mode.
To run performance tests in benchmarking mode:
diff --git a/railties/guides/source/rails_on_rack.textile b/railties/guides/source/rails_on_rack.textile
index d6cbd84b1f..9526526bc7 100644
--- a/railties/guides/source/rails_on_rack.textile
+++ b/railties/guides/source/rails_on_rack.textile
@@ -95,6 +95,7 @@ use ActiveSupport::Cache::Strategy::LocalCache
use Rack::Runtime
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
+use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use Rack::Sendfile
use ActionDispatch::Callbacks
diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile
index 29c729592b..0823fb14e3 100644
--- a/railties/guides/source/routing.textile
+++ b/railties/guides/source/routing.textile
@@ -655,7 +655,7 @@ You can use the +:constraints+ option to specify a required format on the implic
resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/}
</ruby>
-This declaration constraints the +:id+ parameter to match the supplied regular expression. So, in this case, the router would no longer match +/photos/1+ to this route. Instead, +/photos/RR27+ would match.
+This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, the router would no longer match +/photos/1+ to this route. Instead, +/photos/RR27+ would match.
You can specify a single constraint to apply to a number of routes by using the block form:
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index f5f47acfbc..b20634c5a9 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -1,5 +1,4 @@
require 'active_support/core_ext/hash/reverse_merge'
-require 'active_support/file_update_checker'
require 'fileutils'
require 'rails/plugin'
require 'rails/engine'
@@ -33,6 +32,25 @@ module Rails
#
# The Application is also responsible for building the middleware stack.
#
+ # == Booting process
+ #
+ # The application is also responsible for setting up and executing the booting
+ # process. From the moment you require "config/application.rb" in your app,
+ # the booting process goes like this:
+ #
+ # 1) require "config/boot.rb" to setup load paths
+ # 2) require railties and engines
+ # 3) Define Rails.application as "class MyApp::Application < Rails::Application"
+ # 4) Run config.before_configuration callbacks
+ # 5) Load config/environments/ENV.rb
+ # 6) Run config.before_initialize callbacks
+ # 7) Run Railtie#initializer defined by railties, engines and application.
+ # One by one, each engine sets up its load paths, routes and runs its config/initializers/* files.
+ # 9) Custom Railtie#initializers added by railties, engines and applications are executed
+ # 10) Build the middleware stack and run to_prepare callbacks
+ # 11) Run config.before_eager_load and eager_load if cache classes is true
+ # 12) Run config.after_initialize callbacks
+ #
class Application < Engine
autoload :Bootstrap, 'rails/application/bootstrap'
autoload :Configuration, 'rails/application/configuration'
@@ -52,12 +70,14 @@ module Rails
attr_accessor :assets, :sandbox
alias_method :sandbox?, :sandbox
+ attr_reader :reloaders
delegate :default_url_options, :default_url_options=, :to => :routes
def initialize
super
@initialized = false
+ @reloaders = []
end
# This method is called just after an application inherits from Rails::Application,
@@ -83,27 +103,51 @@ module Rails
require environment if environment
end
+ # Reload application routes regardless if they changed or not.
def reload_routes!
routes_reloader.reload!
end
- def routes_reloader
+ def routes_reloader #:nodoc:
@routes_reloader ||= RoutesReloader.new
end
- def initialize!(group=:default)
+ # Returns an array of file paths appended with a hash of directories-extensions
+ # suitable for ActiveSupport::FileUpdateChecker API.
+ def watchable_args
+ files = []
+ files.concat config.watchable_files
+
+ dirs = {}
+ dirs.merge! config.watchable_dirs
+ ActiveSupport::Dependencies.autoload_paths.each do |path|
+ dirs[path.to_s] = [:rb]
+ end
+
+ [files, dirs]
+ end
+
+ # Initialize the application passing the given group. By default, the
+ # group is :default but sprockets precompilation passes group equals
+ # to assets if initialize_on_precompile is false to avoid booting the
+ # whole app.
+ def initialize!(group=:default) #:nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
+ # Load the application and its railties tasks and invoke the registered hooks.
+ # Check <tt>Rails::Railtie.rake_tasks</tt> for more info.
def load_tasks(app=self)
initialize_tasks
super
self
end
+ # Load the application console and invoke the registered hooks.
+ # Check <tt>Rails::Railtie.console</tt> for more info.
def load_console(app=self)
initialize_console
super
@@ -124,12 +168,14 @@ module Rails
"action_dispatch.parameter_filter" => config.filter_parameters,
"action_dispatch.secret_token" => config.secret_token,
"action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
+ "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
"action_dispatch.logger" => Rails.logger,
"action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner
})
end
- def ordered_railties
+ # Returns the ordered railties for this application considering railties_order.
+ def ordered_railties #:nodoc:
@ordered_railties ||= begin
order = config.railties_order.map do |railtie|
if railtie == :main_app
@@ -151,13 +197,13 @@ module Rails
end
end
- def initializers
+ def initializers #:nodoc:
Bootstrap.initializers_for(self) +
super +
Finisher.initializers_for(self)
end
- def config
+ def config #:nodoc:
@config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd))
end
@@ -165,7 +211,7 @@ module Rails
self
end
- def helpers_paths
+ def helpers_paths #:nodoc:
config.helpers_paths
end
@@ -173,6 +219,10 @@ module Rails
alias :build_middleware_stack :app
+ def reload_dependencies?
+ config.reload_classes_only_on_change != true || reloaders.map(&:updated?).any?
+ end
+
def default_middleware_stack
ActionDispatch::MiddlewareStack.new.tap do |middleware|
if rack_cache = config.action_controller.perform_caching && config.action_dispatch.rack_cache
@@ -194,7 +244,7 @@ module Rails
middleware.use ::Rack::MethodOverride
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
+ middleware.use ::ActionDispatch::ShowExceptions, config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path)
middleware.use ::ActionDispatch::DebugExceptions
middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
@@ -202,7 +252,11 @@ module Rails
middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
end
- middleware.use ::ActionDispatch::Reloader unless config.cache_classes
+ unless config.cache_classes
+ app = self
+ middleware.use ::ActionDispatch::Reloader, lambda { app.reload_dependencies? }
+ end
+
middleware.use ::ActionDispatch::Callbacks
middleware.use ::ActionDispatch::Cookies
@@ -222,7 +276,7 @@ module Rails
end
end
- def initialize_tasks
+ def initialize_tasks #:nodoc:
self.class.rake_tasks do
require "rails/tasks"
task :environment do
@@ -232,7 +286,7 @@ module Rails
end
end
- def initialize_console
+ def initialize_console #:nodoc:
require "pp"
require "rails/console/app"
require "rails/console/helpers"
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index c2cb121e42..e189009cc5 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -24,9 +24,18 @@ module Rails
initializer :initialize_logger, :group => :all do
Rails.logger ||= config.logger || begin
path = config.paths["log"].first
- logger = ActiveSupport::TaggedLogging.new(ActiveSupport::BufferedLogger.new(path))
+ unless File.exist? File.dirname path
+ FileUtils.mkdir_p File.dirname path
+ end
+
+ f = File.open path, 'w'
+ f.binmode
+ f.sync = !Rails.env.production? # make sure every write flushes
+
+ logger = ActiveSupport::TaggedLogging.new(
+ ActiveSupport::BufferedLogger.new(f)
+ )
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::TaggedLogging.new(ActiveSupport::BufferedLogger.new(STDERR))
@@ -37,7 +46,6 @@ module Rails
)
logger
end
- at_exit { Rails.logger.flush if Rails.logger.respond_to?(:flush) }
end
# Initialize cache early in the stack so railties can make use of it.
@@ -51,13 +59,6 @@ module Rails
end
end
- initializer :set_clear_dependencies_hook, :group => :all do
- ActionDispatch::Reloader.to_cleanup do
- ActiveSupport::DescendantsTracker.clear
- ActiveSupport::Dependencies.clear
- end
- end
-
# Sets the dependency loading mechanism.
# TODO: Remove files from the $" and always use require.
initializer :initialize_dependency_mechanism, :group => :all do
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index e95b0f5495..a782441a21 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/string/encoding'
require 'active_support/core_ext/kernel/reporting'
+require 'active_support/file_update_checker'
require 'rails/engine/configuration'
module Rails
@@ -7,11 +8,11 @@ module Rails
class Configuration < ::Rails::Engine::Configuration
attr_accessor :allow_concurrency, :asset_host, :asset_path, :assets,
:cache_classes, :cache_store, :consider_all_requests_local,
- :dependency_loading, :filter_parameters,
+ :dependency_loading, :exceptions_app, :file_watcher, :filter_parameters,
: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, :railties_order
+ :railties_order, :relative_url_root, :reload_plugins, :secret_token,
+ :serve_static_assets, :ssl_options, :static_cache_control, :session_options,
+ :time_zone, :reload_classes_only_on_change, :whiny_nils
attr_writer :log_level
attr_reader :encoding
@@ -19,23 +20,27 @@ module Rails
def initialize(*)
super
self.encoding = "utf-8"
- @allow_concurrency = false
- @consider_all_requests_local = false
- @filter_parameters = []
- @helpers_paths = []
- @dependency_loading = true
- @serve_static_assets = true
- @static_cache_control = nil
- @force_ssl = false
- @ssl_options = {}
- @session_store = :cookie_store
- @session_options = {}
- @time_zone = "UTC"
- @log_level = nil
- @middleware = app_middleware
- @generators = app_generators
- @cache_store = [ :file_store, "#{root}/tmp/cache/" ]
- @railties_order = [:all]
+ @allow_concurrency = false
+ @consider_all_requests_local = false
+ @filter_parameters = []
+ @helpers_paths = []
+ @dependency_loading = true
+ @serve_static_assets = true
+ @static_cache_control = nil
+ @force_ssl = false
+ @ssl_options = {}
+ @session_store = :cookie_store
+ @session_options = {}
+ @time_zone = "UTC"
+ @log_level = nil
+ @middleware = app_middleware
+ @generators = app_generators
+ @cache_store = [ :file_store, "#{root}/tmp/cache/" ]
+ @railties_order = [:all]
+ @relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"]
+ @reload_classes_only_on_change = true
+ @file_watcher = ActiveSupport::FileUpdateChecker
+ @exceptions_app = nil
@assets = ActiveSupport::OrderedOptions.new
@assets.enabled = false
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index fc7d205a6f..b9944bed26 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -20,12 +20,6 @@ module Rails
end
end
- initializer :add_to_prepare_blocks do
- config.to_prepare_blocks.each do |block|
- ActionDispatch::Reloader.to_prepare(&block)
- end
- end
-
initializer :add_builtin_route do |app|
if Rails.env.development?
app.routes.append do
@@ -38,14 +32,22 @@ module Rails
build_middleware_stack
end
- initializer :run_prepare_callbacks do
- ActionDispatch::Reloader.prepare!
- end
-
initializer :define_main_app_helper do |app|
app.routes.define_mounted_helper(:main_app)
end
+ initializer :add_to_prepare_blocks do
+ config.to_prepare_blocks.each do |block|
+ ActionDispatch::Reloader.to_prepare(&block)
+ end
+ end
+
+ # This needs to happen before eager load so it happens
+ # in exactly the same point regardless of config.cache_classes
+ initializer :run_prepare_callbacks do
+ ActionDispatch::Reloader.prepare!
+ end
+
initializer :eager_load! do
if config.cache_classes && !$rails_rake_task
ActiveSupport.run_load_hooks(:before_eager_load, self)
@@ -53,17 +55,37 @@ module Rails
end
end
+ # All initialization is done, including eager loading in production
initializer :finisher_hook do
ActiveSupport.run_load_hooks(:after_initialize, self)
end
- # Force routes to be loaded just at the end and add it to to_prepare callbacks
- # This needs to be after the finisher hook to ensure routes added in the hook
- # are still loaded.
- initializer :set_routes_reloader do |app|
- reloader = lambda { app.routes_reloader.execute_if_updated }
- reloader.call
- ActionDispatch::Reloader.to_prepare(&reloader)
+ # Set app reload just after the finisher hook to ensure
+ # routes added in the hook are still loaded.
+ initializer :set_routes_reloader_hook do
+ reloader = routes_reloader
+ reloader.execute_if_updated
+ self.reloaders << reloader
+ ActionDispatch::Reloader.to_prepare { reloader.execute_if_updated }
+ end
+
+ # Set app reload just after the finisher hook to ensure
+ # paths added in the hook are still loaded.
+ initializer :set_clear_dependencies_hook, :group => :all do
+ callback = lambda do
+ ActiveSupport::DescendantsTracker.clear
+ ActiveSupport::Dependencies.clear
+ end
+
+ if config.reload_classes_only_on_change
+ reloader = config.file_watcher.new(*watchable_args, &callback)
+ self.reloaders << reloader
+ # We need to set a to_prepare callback regardless of the reloader result, i.e.
+ # models should be reloaded if any of the reloaders (i18n, routes) were updated.
+ ActionDispatch::Reloader.to_prepare(:prepend => true){ reloader.execute }
+ else
+ ActionDispatch::Reloader.to_cleanup(&callback)
+ end
end
# Disable dependency loading during request cycle
diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb
index 1d1f5e1b06..ef7e733ce4 100644
--- a/railties/lib/rails/application/routes_reloader.rb
+++ b/railties/lib/rails/application/routes_reloader.rb
@@ -1,10 +1,13 @@
+require "active_support/core_ext/module/delegation"
+
module Rails
class Application
- class RoutesReloader < ::ActiveSupport::FileUpdateChecker
- attr_reader :route_sets
+ class RoutesReloader
+ attr_reader :route_sets, :paths
+ delegate :execute_if_updated, :execute, :updated?, :to => :updater
def initialize
- super([]) { reload! }
+ @paths = []
@route_sets = []
end
@@ -16,7 +19,15 @@ module Rails
revert
end
- protected
+ private
+
+ def updater
+ @updater ||= begin
+ updater = ActiveSupport::FileUpdateChecker.new(paths) { reload! }
+ updater.execute
+ updater
+ end
+ end
def clear!
route_sets.each do |routes|
diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb
index 4b0acc9d88..d425c9db6c 100644
--- a/railties/lib/rails/commands/dbconsole.rb
+++ b/railties/lib/rails/commands/dbconsole.rb
@@ -41,7 +41,7 @@ module Rails
abort opt.to_s unless (0..1).include?(ARGV.size)
end
- unless config = YAML::load(ERB.new(IO.read("#{@app.root}/config/database.yml")).result)[Rails.env]
+ unless config = @app.config.database_configuration[Rails.env]
abort "No database is configured for the environment '#{Rails.env}'"
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 5c1af99fe2..20321a502d 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -228,7 +228,7 @@ module Rails
# resources :articles
# end
#
- # The routes above will automatically point to <tt>MyEngine::ApplicationContoller</tt>. Furthermore, you don't
+ # The routes above will automatically point to <tt>MyEngine::ApplicationController</tt>. Furthermore, you don't
# need to use longer url helpers like <tt>my_engine_articles_path</tt>. Instead, you should simply use
# <tt>articles_path</tt> as you would do with your application.
#
@@ -517,7 +517,7 @@ module Rails
# Blog::Engine.load_seed
def load_seed
seed_file = paths["db/seeds"].existent.first
- load(seed_file) if seed_file && File.exist?(seed_file)
+ load(seed_file) if seed_file
end
# Add configured load paths to ruby load paths and remove duplicates.
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index f424492bb4..d6015e9c01 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -30,7 +30,7 @@ module Rails
#
# config.generators.colorize_logging = false
#
- def generators #:nodoc
+ def generators #:nodoc:
@generators ||= Rails::Configuration::Generators.new
yield(@generators) if block_given?
@generators
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 3fbde0d989..197b692469 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -193,16 +193,33 @@ module Rails
end
def assets_gemfile_entry
- <<-GEMFILE.strip_heredoc
- # Gems used only for assets and not required
- # in production environments by default.
- group :assets do
- gem 'sass-rails', :git => 'git://github.com/rails/sass-rails.git'
- gem 'coffee-rails', :git => 'git://github.com/rails/coffee-rails.git'
- #{"gem 'therubyrhino'\n" if defined?(JRUBY_VERSION)}
- gem 'uglifier', '>= 1.0.3'
- end
- GEMFILE
+ return if options[:skip_sprockets]
+
+ gemfile = if options.dev? || options.edge?
+ <<-GEMFILE
+ # Gems used only for assets and not required
+ # in production environments by default.
+ group :assets do
+ gem 'sass-rails', :git => 'git://github.com/rails/sass-rails.git'
+ gem 'coffee-rails', :git => 'git://github.com/rails/coffee-rails.git'
+ #{"gem 'therubyrhino'\n" if defined?(JRUBY_VERSION)}
+ gem 'uglifier', '>= 1.0.3'
+ end
+ GEMFILE
+ else
+ <<-GEMFILE
+ # Gems used only for assets and not required
+ # in production environments by default.
+ group :assets do
+ gem 'sass-rails', '~> 3.2.0'
+ gem 'coffee-rails', '~> 3.2.0'
+ #{"gem 'therubyrhino'\n" if defined?(JRUBY_VERSION)}
+ gem 'uglifier', '>= 1.0.3'
+ end
+ GEMFILE
+ end
+
+ gemfile.strip_heredoc.gsub(/^[ \t]*$/, '')
end
def javascript_gemfile_entry
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 3e32f758a4..2a6bd57df4 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -38,7 +38,7 @@ module Rails
end
def readme
- copy_file "README"
+ copy_file "README", "README.rdoc"
end
def gemfile
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index d3b8f4d595..c260cc999b 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -1,4 +1,4 @@
-source 'http://rubygems.org'
+source 'https://rubygems.org'
<%= rails_gemfile_entry -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index 40fd843b1b..c6dfa1f2dd 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -54,6 +54,12 @@ module <%= app_const_base %>
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
+ # Enforce whitelist mode for mass assignment.
+ # This will create an empty whitelist of attributes available for mass-assignment for all models
+ # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
+ # parameters by using an attr_accessible or attr_protected declaration.
+ # config.active_record.whitelist_attributes = true
+
<% unless options.skip_sprockets? -%>
# Enable the asset pipeline
config.assets.enabled = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index 47078e3af9..9e53b6a70d 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -25,11 +25,17 @@
<%- unless options.skip_active_record? -%>
# Raise exception on mass assignment protection for ActiveRecord models
config.active_record.mass_assignment_sanitizer = :strict
+
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ config.active_record.auto_explain_threshold_in_seconds = 0.5
<%- end -%>
+ <%- unless options.skip_sprockets? -%>
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true
+ <%- end -%>
end
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 50f2df3d35..0f571f7c1a 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
@@ -11,6 +11,7 @@
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = false
+ <%- unless options.skip_sprockets? -%>
# Compress JavaScripts and CSS
config.assets.compress = true
@@ -22,6 +23,7 @@
# Defaults to Rails.root.join("public/assets")
# config.assets.manifest = YOUR_PATH
+ <%- end -%>
# Specifies the header that your server uses for sending files
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
@@ -45,8 +47,10 @@
# Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
+ <%- unless options.skip_sprockets? -%>
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
# config.assets.precompile += %w( search.js )
+ <%- end -%>
# Disable delivery errors, bad email addresses will be ignored
# config.action_mailer.raise_delivery_errors = false
@@ -60,4 +64,10 @@
# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify
+
+ <%- unless options.skip_active_record? -%>
+ # Log the query plan for queries taking more than this (works
+ # with SQLite, MySQL, and PostgreSQL)
+ # config.active_record.auto_explain_threshold_in_seconds = 0.5
+ <%- end -%>
end
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore
index 92bd3c614b..7833c586f3 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/gitignore
@@ -3,4 +3,5 @@ log/*.log
pkg/
<%= dummy_path %>/db/*.sqlite3
<%= dummy_path %>/log/*.log
-<%= dummy_path %>/tmp/ \ No newline at end of file
+<%= dummy_path %>/tmp/
+<%= dummy_path %>/.sass-cache
diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb
index f888684117..cf9e4ad500 100644
--- a/railties/lib/rails/railtie/configuration.rb
+++ b/railties/lib/rails/railtie/configuration.rb
@@ -7,6 +7,18 @@ module Rails
@@options ||= {}
end
+ # Add files that should be watched for change.
+ def watchable_files
+ @@watchable_files ||= []
+ end
+
+ # Add directories that should be watched for change.
+ # The key of the hashes should be directories and the values should
+ # be an array of extensions to match in each directory.
+ def watchable_dirs
+ @@watchable_dirs ||= {}
+ end
+
# This allows you to modify the application's middlewares from Engines.
#
# All operations you run on the app_middleware will be replayed on the
diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb
index 1eed763aa3..2286e0477a 100644
--- a/railties/lib/rails/source_annotation_extractor.rb
+++ b/railties/lib/rails/source_annotation_extractor.rb
@@ -30,7 +30,7 @@ class SourceAnnotationExtractor
# Prints all annotations with tag +tag+ under the root directories +app+, +config+, +lib+,
# +script+, and +test+ (recursively). Only filenames with extension
- # +.builder+, +.rb+, +.rxml+, +.rhtml+, or +.erb+ are taken into account. The +options+
+ # +.builder+, +.rb+, and +.erb+ are taken into account. The +options+
# hash is passed to each annotation's +to_s+.
#
# This class method is the single entry point for the rake tasks.
@@ -46,16 +46,14 @@ class SourceAnnotationExtractor
end
# Returns a hash that maps filenames under +dirs+ (recursively) to arrays
- # with their annotations. Only files with annotations are included, and only
- # those with extension +.builder+, +.rb+, +.rxml+, +.rhtml+, and +.erb+
- # are taken into account.
+ # with their annotations.
def find(dirs=%w(app config lib script test))
dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
end
# Returns a hash that maps filenames under +dir+ (recursively) to arrays
# with their annotations. Only files with annotations are included, and only
- # those with extension +.builder+, +.rb+, +.rxml+, +.rhtml+, and +.erb+
+ # those with extension +.builder+, +.rb+, +.erb+, +.haml+ and +.slim+
# are taken into account.
def find_in(dir)
results = {}
@@ -65,10 +63,14 @@ class SourceAnnotationExtractor
if File.directory?(item)
results.update(find_in(item))
- elsif item =~ /\.(builder|(r(?:b|xml|js)))$/
+ elsif item =~ /\.(builder|rb)$/
results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
- elsif item =~ /\.(rhtml|erb)$/
+ elsif item =~ /\.erb$/
results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
+ elsif item =~ /\.haml$/
+ results.update(extract_annotations_from(item, /-\s*#\s*(#{tag}):?\s*(.*)$/))
+ elsif item =~ /\.slim$/
+ results.update(extract_annotations_from(item, /\/\s*\s*(#{tag}):?\s*(.*)$/))
end
end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index a22013f81c..cc5695091b 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -72,7 +72,7 @@ module ApplicationTests
end
end
- test "precompile application.js and application.css and all other files not ending with .js or .css by default" do
+ test "precompile application.js and application.css and all other non JS/CSS files" do
app_file "app/assets/javascripts/application.js", "alert();"
app_file "app/assets/stylesheets/application.css", "body{}"
@@ -82,8 +82,11 @@ module ApplicationTests
app_file "app/assets/javascripts/something.min.js", "alert();"
app_file "app/assets/stylesheets/something.min.css", "body{}"
+ app_file "app/assets/javascripts/something.else.js.erb", "alert();"
+ app_file "app/assets/stylesheets/something.else.css.erb", "body{}"
+
images_should_compile = ["a.png", "happyface.png", "happy_face.png", "happy.face.png",
- "happy-face.png", "happy.happy_face.png", "happy_happy.face.png",
+ "happy-face.png", "happy.happy_face.png", "happy_happy.face.png",
"happy.happy.face.png", "happy", "happy.face", "-happyface",
"-happy.png", "-happy.face.png", "_happyface", "_happy.face.png",
"_happy.png"]
@@ -106,6 +109,9 @@ module ApplicationTests
assert !File.exists?("#{app_path}/public/assets/something.min.js")
assert !File.exists?("#{app_path}/public/assets/something.min.css")
+
+ assert !File.exists?("#{app_path}/public/assets/something.else.js")
+ assert !File.exists?("#{app_path}/public/assets/something.else.css")
end
test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do
@@ -213,7 +219,9 @@ module ApplicationTests
app_file "app/assets/javascripts/app.js", "alert();"
require "#{app_path}/config/environment"
- class ::PostsController < ActionController::Base ; end
+ class ::PostsController < ActionController::Base
+ def show_detailed_exceptions?() true end
+ end
get '/posts'
assert_match(/AssetNotPrecompiledError/, last_response.body)
@@ -472,6 +480,15 @@ module ApplicationTests
assert_match 'src="//example.com/assets/rails.png"', File.read("#{app_path}/public/assets/image_loader.js")
end
+ test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do
+ ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri"
+
+ app_file "app/assets/javascripts/app.js.erb", 'var src="<%= image_path("rails.png") %>";'
+ add_to_config "config.assets.precompile = %w{app.js}"
+ precompile!
+
+ assert_match 'src="/sub/uri/assets/rails.png"', File.read("#{app_path}/public/assets/app.js")
+ end
private
diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb
index 2073c780bf..fa2652a6d3 100644
--- a/railties/test/application/console_test.rb
+++ b/railties/test/application/console_test.rb
@@ -61,7 +61,6 @@ class ConsoleTest < Test::Unit::TestCase
load_environment
assert User.new.respond_to?(:name)
- assert !User.new.respond_to?(:age)
app_file "app/models/user.rb", <<-MODEL
class User
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index 446c85d65a..cf6c4d8fc2 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -136,6 +136,13 @@ module ApplicationTests
assert_equal 2, ActionDispatch::Http::URL.tld_length
end
+ test "assignment config.encoding to default_charset" do
+ charset = "ruby".respond_to?(:force_encoding) ? 'Shift_JIS' : 'UTF8'
+ add_to_config "config.encoding = '#{charset}'"
+ require "#{app_path}/config/environment"
+ assert_equal charset, ActionDispatch::Response.default_charset
+ end
+
# AS
test "if there's no config.active_support.bare, all of ActiveSupport is required" do
use_frameworks []
diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb
index 8c2c079fb8..305ae7eb0a 100644
--- a/railties/test/application/initializers/i18n_test.rb
+++ b/railties/test/application/initializers/i18n_test.rb
@@ -120,6 +120,9 @@ en:
get "/i18n"
assert_equal "1", last_response.body
+ # Wait a full second so we have time for changes to propagate
+ sleep(1)
+
app_file "config/locales/en.yml", <<-YAML
en:
foo: "2"
diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb
index 47c6fd5c6e..c4c93cce22 100644
--- a/railties/test/application/loading_test.rb
+++ b/railties/test/application/loading_test.rb
@@ -16,7 +16,7 @@ class LoadingTest < Test::Unit::TestCase
@app ||= Rails.application
end
- def test_constants_in_app_are_autoloaded
+ test "constants in app are autoloaded" do
app_file "app/models/post.rb", <<-MODEL
class Post < ActiveRecord::Base
validates_acceptance_of :title, :accept => "omg"
@@ -33,7 +33,7 @@ class LoadingTest < Test::Unit::TestCase
assert_equal 'omg', p.title
end
- def test_models_without_table_do_not_panic_on_scope_definitions_when_loaded
+ test "models without table do not panic on scope definitions when loaded" do
app_file "app/models/user.rb", <<-MODEL
class User < ActiveRecord::Base
default_scope where(:published => true)
@@ -63,9 +63,10 @@ class LoadingTest < Test::Unit::TestCase
assert ::AppTemplate::Application.config.loaded
end
- def test_descendants_are_cleaned_on_each_request_without_cache_classes
+ test "descendants are cleaned on each request without cache classes" do
add_to_config <<-RUBY
config.cache_classes = false
+ config.reload_classes_only_on_change = false
RUBY
app_file "app/models/post.rb", <<-MODEL
@@ -98,6 +99,162 @@ class LoadingTest < Test::Unit::TestCase
assert_raise(RuntimeError) { ::AppTemplate::Application.initialize! }
end
+ test "reload constants on development" do
+ add_to_config <<-RUBY
+ config.cache_classes = false
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match '/c', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
+ end
+ RUBY
+
+ app_file "app/models/user.rb", <<-MODEL
+ class User
+ def self.counter; 1; end
+ end
+ MODEL
+
+ require 'rack/test'
+ extend Rack::Test::Methods
+
+ require "#{rails_root}/config/environment"
+
+ get "/c"
+ assert_equal "1", last_response.body
+
+ app_file "app/models/user.rb", <<-MODEL
+ class User
+ def self.counter; 2; end
+ end
+ MODEL
+
+ get "/c"
+ assert_equal "2", last_response.body
+ end
+
+ test "does not reload constants on development if custom file watcher always returns false" do
+ add_to_config <<-RUBY
+ config.cache_classes = false
+ config.file_watcher = Class.new do
+ def initialize(*); end
+ def updated?; false; end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match '/c', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
+ end
+ RUBY
+
+ app_file "app/models/user.rb", <<-MODEL
+ class User
+ def self.counter; 1; end
+ end
+ MODEL
+
+ require 'rack/test'
+ extend Rack::Test::Methods
+
+ require "#{rails_root}/config/environment"
+
+ get "/c"
+ assert_equal "1", last_response.body
+
+ app_file "app/models/user.rb", <<-MODEL
+ class User
+ def self.counter; 2; end
+ end
+ MODEL
+
+ get "/c"
+ assert_equal "1", last_response.body
+ end
+
+ test "added files (like db/schema.rb) also trigger reloading" do
+ add_to_config <<-RUBY
+ config.cache_classes = false
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ $counter = 0
+ AppTemplate::Application.routes.draw do
+ match '/c', :to => lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] }
+ end
+ RUBY
+
+ app_file "app/models/user.rb", <<-MODEL
+ class User
+ $counter += 1
+ end
+ MODEL
+
+ require 'rack/test'
+ extend Rack::Test::Methods
+
+ require "#{rails_root}/config/environment"
+
+ get "/c"
+ assert_equal "1", last_response.body
+
+ app_file "db/schema.rb", ""
+
+ get "/c"
+ assert_equal "2", last_response.body
+ end
+
+ test "columns migrations also trigger reloading" do
+ add_to_config <<-RUBY
+ config.cache_classes = false
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match '/title', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.title]] }
+ match '/body', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.body]] }
+ end
+ RUBY
+
+ app_file "app/models/post.rb", <<-MODEL
+ class Post < ActiveRecord::Base
+ end
+ MODEL
+
+ require 'rack/test'
+ extend Rack::Test::Methods
+
+ app_file "db/migrate/1_create_posts.rb", <<-MIGRATION
+ class CreatePosts < ActiveRecord::Migration
+ def change
+ create_table :posts do |t|
+ t.string :title, :default => "TITLE"
+ end
+ end
+ end
+ MIGRATION
+
+ Dir.chdir(app_path) { `rake db:migrate`}
+ require "#{rails_root}/config/environment"
+
+ get "/title"
+ assert_equal "TITLE", last_response.body
+
+ app_file "db/migrate/2_add_body_to_posts.rb", <<-MIGRATION
+ class AddBodyToPosts < ActiveRecord::Migration
+ def change
+ add_column :posts, :body, :text, :default => "BODY"
+ end
+ end
+ MIGRATION
+
+ Dir.chdir(app_path) { `rake db:migrate` }
+
+ get "/body"
+ assert_equal "BODY", last_response.body
+ end
+
protected
def setup_ar!
diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb
index 050a2161ae..790c5b2d53 100644
--- a/railties/test/application/middleware/cache_test.rb
+++ b/railties/test/application/middleware/cache_test.rb
@@ -54,9 +54,9 @@ module ApplicationTests
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
diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb
index 0174352900..a9cde42be8 100644
--- a/railties/test/application/middleware/exceptions_test.rb
+++ b/railties/test/application/middleware/exceptions_test.rb
@@ -45,7 +45,21 @@ module ApplicationTests
assert_equal 404, last_response.status
end
- test "unspecified route when set action_dispatch.show_exceptions to false" do
+ test "uses custom exceptions app" do
+ add_to_config <<-RUBY
+ config.exceptions_app = lambda do |env|
+ [404, { "Content-Type" => "text/plain" }, ["YOU FAILED BRO"]]
+ end
+ RUBY
+
+ app.config.action_dispatch.show_exceptions = true
+
+ get "/foo"
+ assert_equal 404, last_response.status
+ assert_equal "YOU FAILED BRO", last_response.body
+ end
+
+ test "unspecified route when action_dispatch.show_exceptions is not set raises an exception" do
app.config.action_dispatch.show_exceptions = false
assert_raise(ActionController::RoutingError) do
@@ -53,16 +67,28 @@ module ApplicationTests
end
end
- test "unspecified route when set action_dispatch.show_exceptions to true" do
+ test "unspecified route when action_dispatch.show_exceptions is set shows 404" do
+ app.config.action_dispatch.show_exceptions = true
+
+ assert_nothing_raised(ActionController::RoutingError) do
+ get '/foo'
+ assert_match "The page you were looking for doesn't exist.", last_response.body
+ end
+ end
+
+ test "unspecified route when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
app.config.action_dispatch.show_exceptions = true
+ app.config.consider_all_requests_local = true
assert_nothing_raised(ActionController::RoutingError) do
get '/foo'
+ assert_match "No route matches", last_response.body
end
end
test "displays diagnostics message when exception raised in template that contains UTF-8" do
app.config.action_dispatch.show_exceptions = true
+ app.config.consider_all_requests_local = true
controller :foo, <<-RUBY
class FooController < ActionController::Base
diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb
new file mode 100644
index 0000000000..7982c42d8f
--- /dev/null
+++ b/railties/test/application/rake/migrations_test.rb
@@ -0,0 +1,109 @@
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ module RakeTests
+ class RakeMigrationsTest < Test::Unit::TestCase
+ def setup
+ build_app
+ boot_rails
+ FileUtils.rm_rf("#{app_path}/config/environments")
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test 'running migrations with given scope' do
+ Dir.chdir(app_path) do
+ `rails generate model user username:string password:string`
+ end
+ app_file "db/migrate/01_a_migration.bukkits.rb", <<-MIGRATION
+ class AMigration < ActiveRecord::Migration
+ end
+ MIGRATION
+
+ output = Dir.chdir(app_path) { `rake db:migrate SCOPE=bukkits` }
+ assert_no_match(/create_table\(:users\)/, output)
+ assert_no_match(/CreateUsers/, output)
+ assert_no_match(/add_column\(:users, :email, :string\)/, output)
+
+ assert_match(/AMigration: migrated/, output)
+
+ output = Dir.chdir(app_path) { `rake db:migrate SCOPE=bukkits VERSION=0` }
+ assert_no_match(/drop_table\(:users\)/, output)
+ assert_no_match(/CreateUsers/, output)
+ assert_no_match(/remove_column\(:users, :email\)/, output)
+
+ assert_match(/AMigration: reverted/, output)
+ end
+
+ test 'model and migration generator with change syntax' do
+ Dir.chdir(app_path) do
+ `rails generate model user username:string password:string`
+ `rails generate migration add_email_to_users email:string`
+ end
+
+ output = Dir.chdir(app_path){ `rake db:migrate` }
+ assert_match(/create_table\(:users\)/, output)
+ assert_match(/CreateUsers: migrated/, output)
+ assert_match(/add_column\(:users, :email, :string\)/, output)
+ assert_match(/AddEmailToUsers: migrated/, output)
+
+ output = Dir.chdir(app_path){ `rake db:rollback STEP=2` }
+ assert_match(/drop_table\("users"\)/, output)
+ assert_match(/CreateUsers: reverted/, output)
+ assert_match(/remove_column\("users", :email\)/, output)
+ assert_match(/AddEmailToUsers: reverted/, output)
+ end
+
+ test 'migration status when schema migrations table is not present' do
+ output = Dir.chdir(app_path){ `rake db:migrate:status` }
+ assert_equal "Schema migrations table does not exist yet.\n", output
+ end
+
+ test 'test migration status' do
+ Dir.chdir(app_path) do
+ `rails generate model user username:string password:string`
+ `rails generate migration add_email_to_users email:string`
+ end
+
+ Dir.chdir(app_path) { `rake db:migrate`}
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+
+ Dir.chdir(app_path) { `rake db:rollback STEP=1` }
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/down\s+\d{14}\s+Add email to users/, output)
+ end
+
+ test 'test migration status after rollback and redo' do
+ Dir.chdir(app_path) do
+ `rails generate model user username:string password:string`
+ `rails generate migration add_email_to_users email:string`
+ end
+
+ Dir.chdir(app_path) { `rake db:migrate` }
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+
+ Dir.chdir(app_path) { `rake db:rollback STEP=2` }
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/down\s+\d{14}\s+Create users/, output)
+ assert_match(/down\s+\d{14}\s+Add email to users/, output)
+
+ Dir.chdir(app_path) { `rake db:migrate:redo` }
+ output = Dir.chdir(app_path) { `rake db:migrate:status` }
+
+ assert_match(/up\s+\d{14}\s+Create users/, output)
+ assert_match(/up\s+\d{14}\s+Add email to users/, output)
+ end
+ end
+ end
+end
diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb
new file mode 100644
index 0000000000..659cbfec0f
--- /dev/null
+++ b/railties/test/application/rake/notes_test.rb
@@ -0,0 +1,45 @@
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ module RakeTests
+ class RakeNotesTest < Test::Unit::TestCase
+ def setup
+ build_app
+ require "rails/all"
+ end
+
+ def teardown
+ teardown_app
+ end
+
+ test 'notes' do
+
+ app_file "app/views/home/index.html.erb", "<% # TODO: note in erb %>"
+ app_file "app/views/home/index.html.haml", "-# TODO: note in haml"
+ app_file "app/views/home/index.html.slim", "/ TODO: note in slim"
+
+ boot_rails
+ require 'rake'
+ require 'rdoc/task'
+ require 'rake/testtask'
+
+ Rails.application.load_tasks
+
+ Dir.chdir(app_path) do
+ output = `bundle exec rake notes`
+
+ assert_match /note in erb/, output
+ assert_match /note in haml/, output
+ assert_match /note in slim/, output
+ end
+
+ end
+
+ private
+ def boot_rails
+ super
+ require "#{app_path}/config/environment"
+ end
+ end
+ end
+end
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index c76bc3d526..4e406f23d2 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -108,74 +108,6 @@ module ApplicationTests
assert_match "Sample log message", output
end
- def test_model_and_migration_generator_with_change_syntax
- Dir.chdir(app_path) do
- `rails generate model user username:string password:string`
- `rails generate migration add_email_to_users email:string`
- end
-
- output = Dir.chdir(app_path){ `rake db:migrate` }
- assert_match(/create_table\(:users\)/, output)
- assert_match(/CreateUsers: migrated/, output)
- assert_match(/add_column\(:users, :email, :string\)/, output)
- assert_match(/AddEmailToUsers: migrated/, output)
-
- output = Dir.chdir(app_path){ `rake db:rollback STEP=2` }
- assert_match(/drop_table\("users"\)/, output)
- assert_match(/CreateUsers: reverted/, output)
- assert_match(/remove_column\("users", :email\)/, output)
- assert_match(/AddEmailToUsers: reverted/, output)
- end
-
- def test_migration_status_when_schema_migrations_table_is_not_present
- output = Dir.chdir(app_path){ `rake db:migrate:status` }
- assert_equal "Schema migrations table does not exist yet.\n", output
- end
-
- def test_migration_status
- Dir.chdir(app_path) do
- `rails generate model user username:string password:string`
- `rails generate migration add_email_to_users email:string`
- end
-
- Dir.chdir(app_path) { `rake db:migrate`}
- output = Dir.chdir(app_path) { `rake db:migrate:status` }
-
- assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/up\s+\d{14}\s+Add email to users/, output)
-
- Dir.chdir(app_path) { `rake db:rollback STEP=1` }
- output = Dir.chdir(app_path) { `rake db:migrate:status` }
-
- assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/down\s+\d{14}\s+Add email to users/, output)
- end
-
- def test_migration_status_after_rollback_and_redo
- Dir.chdir(app_path) do
- `rails generate model user username:string password:string`
- `rails generate migration add_email_to_users email:string`
- end
-
- Dir.chdir(app_path) { `rake db:migrate`}
- output = Dir.chdir(app_path) { `rake db:migrate:status` }
-
- assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/up\s+\d{14}\s+Add email to users/, output)
-
- Dir.chdir(app_path) { `rake db:rollback STEP=2` }
- output = Dir.chdir(app_path) { `rake db:migrate:status` }
-
- assert_match(/down\s+\d{14}\s+Create users/, output)
- assert_match(/down\s+\d{14}\s+Add email to users/, output)
-
- Dir.chdir(app_path) { `rake db:migrate:redo` }
- output = Dir.chdir(app_path) { `rake db:migrate:status` }
-
- assert_match(/up\s+\d{14}\s+Create users/, output)
- assert_match(/up\s+\d{14}\s+Add email to users/, output)
- end
-
def test_loading_specific_fixtures
Dir.chdir(app_path) do
`rails generate model user username:string password:string`
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index c1fd6a38f1..ee288871de 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -114,7 +114,7 @@ class ActionsTest < Rails::Generators::TestCase
action :gem_group, :test do
gem 'fakeweb'
end
-
+
assert_file 'Gemfile', /\ngroup :development, :test do\n gem "rspec-rails"\nend\n\ngroup :test do\n gem "fakeweb"\nend/
end
@@ -233,14 +233,14 @@ class ActionsTest < Rails::Generators::TestCase
def test_readme
run_generator
Rails::Generators::AppGenerator.expects(:source_root).times(2).returns(destination_root)
- assert_match(/Welcome to Rails/, action(:readme, "README"))
+ assert_match(/Welcome to Rails/, action(:readme, "README.rdoc"))
end
def test_readme_with_quiet
generator(default_arguments, :quiet => true)
run_generator
Rails::Generators::AppGenerator.expects(:source_root).times(2).returns(destination_root)
- assert_no_match(/Welcome to Rails/, action(:readme, "README"))
+ assert_no_match(/Welcome to Rails/, action(:readme, "README.rdoc"))
end
def test_log
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 235c08e38e..30fbe74e83 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -124,6 +124,16 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "hats/config/environment.rb", /Hats::Application\.initialize!/
end
+ def test_gemfile_has_no_whitespace_errors
+ run_generator
+ absolute = File.expand_path("Gemfile", destination_root)
+ File.open(absolute, 'r') do |f|
+ f.each_line do |line|
+ assert_no_match /^[ \t]+$/, line
+ end
+ end
+ end
+
def test_config_database_is_added_by_default
run_generator
assert_file "config/database.yml", /sqlite3/
@@ -206,13 +216,29 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content)
assert_no_match(/config\.assets\.enabled = true/, content)
end
+ assert_file "Gemfile" do |content|
+ assert_no_match(/sass-rails/, content)
+ assert_no_match(/coffee-rails/, content)
+ assert_no_match(/uglifier/, content)
+ end
+ assert_file "config/environments/development.rb" do |content|
+ assert_no_match(/config\.assets\.debug = true/, content)
+ end
+ assert_file "config/environments/production.rb" do |content|
+ assert_no_match(/config\.assets\.digest = true/, content)
+ assert_no_match(/config\.assets\.compress = true/, content)
+ end
assert_file "test/performance/browsing_test.rb"
end
def test_inclusion_of_therubyrhino_under_jruby
+ run_generator([destination_root])
if defined?(JRUBY_VERSION)
- run_generator([destination_root])
assert_file "Gemfile", /gem\s+["']therubyrhino["']$/
+ else
+ assert_file "Gemfile" do |content|
+ assert_no_match(/gem\s+["']therubyrhino["']$/, content)
+ end
end
end
@@ -329,13 +355,22 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_generated_environments_file_for_sanitizer
run_generator [destination_root, "--skip-active-record"]
- ["config/environments/development.rb", "config/environments/test.rb"].each do |env_file|
- assert_file env_file do |file|
+ %w(development test).each do |env|
+ assert_file "config/environments/#{env}.rb" do |file|
assert_no_match(/config.active_record.mass_assignment_sanitizer = :strict/, file)
end
end
end
+ def test_generated_environments_file_for_auto_explain
+ run_generator [destination_root, "--skip-active-record"]
+ %w(development production).each do |env|
+ assert_file "config/environments/#{env}.rb" do |file|
+ assert_no_match %r(auto_explain_threshold_in_seconds), file
+ end
+ end
+ end
+
protected
def action(*args, &block)
diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb
index 7653e52d26..a15dae2a0a 100644
--- a/railties/test/railties/shared_tests.rb
+++ b/railties/test/railties/shared_tests.rb
@@ -56,6 +56,8 @@ module RailtiesTest
app_file "db/migrate/1_create_sessions.rb", <<-RUBY
class CreateSessions < ActiveRecord::Migration
+ def up
+ end
end
RUBY
@@ -76,19 +78,19 @@ module RailtiesTest
Dir.chdir(app_path) do
output = `bundle exec rake bukkits:install:migrations`
- assert File.exists?("#{app_path}/db/migrate/2_create_users.rb")
- assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.rb")
- assert_match(/Copied migration 2_create_users.rb from bukkits/, output)
- assert_match(/Copied migration 3_add_last_name_to_users.rb from bukkits/, output)
+ assert File.exists?("#{app_path}/db/migrate/2_create_users.bukkits.rb")
+ assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb")
+ assert_match(/Copied migration 2_create_users.bukkits.rb from bukkits/, output)
+ assert_match(/Copied migration 3_add_last_name_to_users.bukkits.rb from bukkits/, output)
assert_match(/NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output)
assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length
output = `bundle exec rake railties:install:migrations`.split("\n")
- assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.rb")
+ assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.acts_as_yaffle.rb")
assert_no_match(/2_create_users/, output.join("\n"))
- yaffle_migration_order = output.index(output.detect{|o| /Copied migration 4_create_yaffles.rb from acts_as_yaffle/ =~ o })
+ yaffle_migration_order = output.index(output.detect{|o| /Copied migration 4_create_yaffles.acts_as_yaffle.rb from acts_as_yaffle/ =~ o })
bukkits_migration_order = output.index(output.detect{|o| /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/ =~ o })
assert_not_nil yaffle_migration_order, "Expected migration to be copied"
assert_not_nil bukkits_migration_order, "Expected migration to be skipped"