aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md11
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb9
-rw-r--r--actionpack/lib/action_dispatch/request/utils.rb4
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request/query_string_parsing_test.rb4
-rw-r--r--actionview/CHANGELOG.md7
-rw-r--r--actionview/lib/action_view/helpers/capture_helper.rb2
-rw-r--r--actionview/test/template/capture_helper_test.rb4
-rw-r--r--actionview/test/template/tag_helper_test.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb6
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb36
-rw-r--r--guides/source/action_controller_overview.md4
-rw-r--r--guides/source/active_record_querying.md2
-rw-r--r--guides/source/constant_autoloading_and_reloading.md277
-rw-r--r--guides/source/layouts_and_rendering.md5
-rw-r--r--guides/source/security.md8
-rw-r--r--railties/lib/rails/generators/app_base.rb10
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile4
-rw-r--r--railties/test/generators/app_generator_test.rb18
19 files changed, 219 insertions, 200 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 3b02994459..115ad54190 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Stop converting empty arrays in `params` to `nil`
+
+ This behaviour was introduced in response to CVE-2012-2660, CVE-2012-2694
+ and CVE-2013-0155
+
+ ActiveRecord now issues a safe query when passing an empty array into
+ a where clause, so there is no longer a need to defend against this type
+ of input (any nils are still stripped from the array).
+
+ *Chris Sinjakli*
+
* Fixed usage of optional scopes in URL helpers.
*Alex Robbin*
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index d3f93a5352..87609d8aa7 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -53,15 +53,6 @@ module ActionController
end
end
- def deep_munge(event)
- debug do
- "Value for params[:#{event.payload[:keys].join('][:')}] was set "\
- "to nil, because it was one of [], [null] or [null, null, ...]. "\
- "Go to http://guides.rubyonrails.org/security.html#unsafe-query-generation "\
- "for more information."\
- end
- end
-
%w(write_fragment read_fragment exist_fragment?
expire_fragment expire_page write_page).each do |method|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb
index 9d4f1aa3c5..1c9371d89c 100644
--- a/actionpack/lib/action_dispatch/request/utils.rb
+++ b/actionpack/lib/action_dispatch/request/utils.rb
@@ -16,10 +16,6 @@ module ActionDispatch
when Array
v.grep(Hash) { |x| deep_munge(x, keys) }
v.compact!
- if v.empty?
- hash[k] = nil
- ActiveSupport::Notifications.instrument("deep_munge.action_controller", keys: keys)
- end
when Hash
deep_munge(v, keys)
end
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index c609075e6b..b765a13fa1 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -39,7 +39,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
test "nils are stripped from collections" do
assert_parses(
- {"person" => nil},
+ {"person" => []},
"{\"person\":[null]}", { 'CONTENT_TYPE' => 'application/json' }
)
assert_parses(
@@ -47,7 +47,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
"{\"person\":[\"foo\",null]}", { 'CONTENT_TYPE' => 'application/json' }
)
assert_parses(
- {"person" => nil},
+ {"person" => []},
"{\"person\":[null, null]}", { 'CONTENT_TYPE' => 'application/json' }
)
end
diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb
index 4e99c26e03..50daafbb54 100644
--- a/actionpack/test/dispatch/request/query_string_parsing_test.rb
+++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb
@@ -95,8 +95,8 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
assert_parses({"action" => nil}, "action")
assert_parses({"action" => {"foo" => nil}}, "action[foo]")
assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar]")
- assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar][]")
- assert_parses({"action" => {"foo" => nil }}, "action[foo][]")
+ assert_parses({"action" => {"foo" => { "bar" => [] }}}, "action[foo][bar][]")
+ assert_parses({"action" => {"foo" => [] }}, "action[foo][]")
assert_parses({"action"=>{"foo"=>[{"bar"=>nil}]}}, "action[foo][][bar]")
end
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index dbdf682614..729717608f 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,8 +1 @@
Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/actionview/CHANGELOG.md) for previous changes.
-
-* Restore old behaviour for `capture` to return value as is when passed non-String values.
-
- Fixes #17661.
-
- *Carsten Zimmermann*
-
diff --git a/actionview/lib/action_view/helpers/capture_helper.rb b/actionview/lib/action_view/helpers/capture_helper.rb
index 7884e4f1f1..75d1634b2e 100644
--- a/actionview/lib/action_view/helpers/capture_helper.rb
+++ b/actionview/lib/action_view/helpers/capture_helper.rb
@@ -36,7 +36,7 @@ module ActionView
def capture(*args)
value = nil
buffer = with_output_buffer { value = yield(*args) }
- if string = buffer.presence || value
+ if string = buffer.presence || value and string.is_a?(String)
ERB::Util.html_escape string
end
end
diff --git a/actionview/test/template/capture_helper_test.rb b/actionview/test/template/capture_helper_test.rb
index b2b8513d4f..f213da5934 100644
--- a/actionview/test/template/capture_helper_test.rb
+++ b/actionview/test/template/capture_helper_test.rb
@@ -24,8 +24,8 @@ class CaptureHelperTest < ActionView::TestCase
assert_equal 'foobar', string
end
- def test_capture_returns_value_even_if_the_returned_value_is_not_a_string
- assert_equal '1', @av.capture { 1 }
+ def test_capture_returns_nil_if_the_returned_value_is_not_a_string
+ assert_nil @av.capture { 1 }
end
def test_capture_escapes_html
diff --git a/actionview/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb
index 2b3915edcd..7fc798dec9 100644
--- a/actionview/test/template/tag_helper_test.rb
+++ b/actionview/test/template/tag_helper_test.rb
@@ -65,8 +65,8 @@ class TagHelperTest < ActionView::TestCase
end
def test_content_tag_with_block_and_non_string_outside_out_of_erb
- assert_equal content_tag("p", "1.0", nil, false),
- content_tag("p") { 1.0 }
+ assert_equal content_tag("p"),
+ content_tag("p") { 3.times { "do_something" } }
end
def test_content_tag_nested_in_content_tag_out_of_erb
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index dc4e767e9d..55ad384f4f 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -10,7 +10,11 @@ class DateTime
end
end
- # Seconds since midnight: DateTime.now.seconds_since_midnight.
+ # Returns the number of seconds since 00:00:00.
+ #
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
def seconds_since_midnight
sec + (min * 60) + (hour * 3600)
end
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 9703fb6d28..fb10b40b84 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -252,9 +252,23 @@ module ActiveSupport
utc.hash
end
+ # Adds an interval of time to the current object's time and return that
+ # value as a new TimeWithZone object.
+ #
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08 EDT -04:00
+ #
+ # If we're adding a Duration of variable length (i.e., years, months, days),
+ # move forward from #time, otherwise move forward from #utc, for accuracy
+ # when moving across DST boundaries.
+ #
+ # For instance, a time + 24.hours will advance exactly 24 hours, while a
+ # time + 1.day will advance 23-25 hours, depending on the day.
+ #
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28 EST -05:00
def +(other)
- # If we're adding a Duration of variable length (i.e., years, months, days), move forward from #time,
- # otherwise move forward from #utc, for accuracy when moving across DST boundaries
if duration_of_variable_length?(other)
method_missing(:+, other)
else
@@ -263,9 +277,23 @@ module ActiveSupport
end
end
+ # Returns a new TimeWithZone object that represents the difference between
+ # the current object's time and the +other+ time.
+ #
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EST -05:00
+ # now - 1000 # => Sun, 02 Nov 2014 01:09:48 EST -05:00
+ #
+ # If subtracting a Duration of variable length (i.e., years, months, days),
+ # move backward from #time, otherwise move backward from #utc, for accuracy
+ # when moving across DST boundaries.
+ #
+ # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
+ # time - 1.day will subtract 23-25 hours, depending on the day.
+ #
+ # now - 24.hours # => Sat, 01 Nov 2014 02:26:28 EDT -04:00
+ # now - 1.day # => Sat, 01 Nov 2014 01:26:28 EDT -04:00
def -(other)
- # If we're subtracting a Duration of variable length (i.e., years, months, days), move backwards from #time,
- # otherwise move backwards #utc, for accuracy when moving across DST boundaries
if other.acts_like?(:time)
to_time - other.to_time
elsif duration_of_variable_length?(other)
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 4e36a62583..57546da389 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -112,8 +112,8 @@ NOTE: The actual URL in this example will be encoded as "/clients?ids%5b%5d=1&id
The value of `params[:ids]` will now be `["1", "2", "3"]`. Note that parameter values are always strings; Rails makes no attempt to guess or cast the type.
-NOTE: Values such as `[]`, `[nil]` or `[nil, nil, ...]` in `params` are replaced
-with `nil` for security reasons by default. See [Security Guide](security.html#unsafe-query-generation)
+NOTE: Values such as `[nil]` or `[nil, nil, ...]` in `params` are replaced
+with `[]` for security reasons by default. See [Security Guide](security.html#unsafe-query-generation)
for more information.
To send a hash you include the key name inside the brackets:
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index a32265e0db..f6fbc29707 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -1365,7 +1365,7 @@ and ignore the others.
Find or Build a New Object
--------------------------
-NOTE: Some dynamic finders have been deprecated in Rails 4.0 and will be
+NOTE: Some dynamic finders were deprecated in Rails 4.0 and
removed in Rails 4.1. The best practice is to use Active Record scopes
instead. You can find the deprecation gem at
https://github.com/rails/activerecord-deprecated_finders
diff --git a/guides/source/constant_autoloading_and_reloading.md b/guides/source/constant_autoloading_and_reloading.md
index 88098236a0..a6b270e06d 100644
--- a/guides/source/constant_autoloading_and_reloading.md
+++ b/guides/source/constant_autoloading_and_reloading.md
@@ -15,8 +15,6 @@ After reading this guide, you will know:
* How constant reloading works
-* That autoloading is not based on `Module#autoload`
-
* Solutions to common autoloading gotchas
--------------------------------------------------------------------------------
@@ -25,11 +23,9 @@ After reading this guide, you will know:
Introduction
------------
-Ruby on Rails allows applications to be written as if all their code was
-preloaded.
+Ruby on Rails allows applications to be written as if their code was preloaded.
-For example, in a normal Ruby program a class like the following controller
-would need to load its dependencies:
+In a normal Ruby program a class needs to load its dependencies:
```ruby
require 'application_controller'
@@ -43,7 +39,7 @@ end
```
Our Rubyist instinct quickly sees some redundancy in there: If classes were
-defined in files matching their name, couldn't their loading maybe be automated
+defined in files matching their name, couldn't their loading be automated
somehow? We could save scanning the file for dependencies, which is brittle.
Moreover, `Kernel#require` loads files once, but development is much more smooth
@@ -51,7 +47,7 @@ if code gets refreshed when it changes without restarting the server. It would
be nice to be able to use `Kernel#load` in development, and `Kernel#require` in
production.
-Indeed, those features are provided by Ruby on Rails, where we just write this:
+Indeed, those features are provided by Ruby on Rails, where we just write
```ruby
class PostsController < ApplicationController
@@ -125,7 +121,7 @@ module X::Y
end
```
-The nesting in (3) is composed of two module objects:
+The nesting in (3) consists of two module objects:
```ruby
[A::B, X::Y]
@@ -143,16 +139,19 @@ executed, and popped after it.
* The module object following a `module` keyword gets pushed when its body is
executed, and popped after it.
-* When a singleton class is opened with `class << object`, the singleton class
-gets pushed when the body is executed, and popped after it.
+* A singleton class opened with `class << object` gets pushed, and popped later.
* When any of the `*_eval` family of methods is called using a string argument,
the singleton class of the receiver is pushed to the nesting of the eval'ed
code.
-It is interesting to observe that **no** block gets a modified nesting. In
-particular the blocks that may be passed to `Class.new` and `Module.new` do not
-get the class or module being defined pushed to their nesting. That's one of the
+* The nesting at the top-level of code interpreted by `Kernel#load` is empty
+unless the `load` call receives a true value as second argument, in which case
+a newly created anonymous module is pushed by Ruby.
+
+It is interesting to observe that blocks do not modify the stack. In particular
+the blocks that may be passed to `Class.new` and `Module.new` do not get the
+class or module being defined pushed to their nesting. That's one of the
differences between defining classes and modules in one way or another.
The nesting at any given place can be inspected with `Module.nesting`.
@@ -183,7 +182,7 @@ performs a constant assignment equivalent to
Project = Class.new(ActiveRecord::Base)
```
-Similarly, module creation using the `module` keyword:
+Similarly, module creation using the `module` keyword as in
```ruby
module Admin
@@ -198,8 +197,8 @@ Admin = Module.new
WARNING. The execution context of a block passed to `Class.new` or `Module.new`
is not entirely equivalent to the one of the body of the definitions using the
-`class` and `module` keywords. But as far as this guide concerns, both idioms
-perform the same constant assignment.
+`class` and `module` keywords. But both idioms result in the same constant
+assignment.
Thus, when one informally says "the `String` class", that really means: the
class object the interpreter creates and stores in a constant called "String" in
@@ -207,7 +206,7 @@ the class object stored in the `Object` constant. `String` is otherwise an
ordinary Ruby constant and everything related to constants applies to it,
resolution algorithms, etc.
-Similarly, in the controller
+Likewise, in the controller
```ruby
class PostsController < ApplicationController
@@ -255,10 +254,12 @@ that may live in any other class or module object. If there were any, they
would have separate entries in their respective constant tables.
Put special attention in the previous paragraphs to the distinction between
-class and module objects, constant names, and value objects assiociated to them
+class and module objects, constant names, and value objects associated to them
in constant tables.
-### Resolution Algorithm for Relative Constants
+### Resolution Algorithms
+
+#### Resolution Algorithm for Relative Constants
At any given place in the code, let's define *cref* to be the first element of
the nesting if it is not empty, or `Object` otherwise.
@@ -271,13 +272,14 @@ order. The ancestors of those elements are ignored.
2. If not found, then the algorithm walks up the ancestor chain of the cref.
-3. If not found, `const_missing` is invoked on the cref.
+3. If not found, `const_missing` is invoked on the cref. The default
+implementation of `const_missing` raises `NameError`, but it can be overridden.
Rails autoloading **does not emulate this algorithm**, but its starting point is
the name of the constant to be autoloaded, and the cref. See more in [Relative
References](#relative-references).
-### Resolution Algorithm for Qualified Constants
+#### Resolution Algorithm for Qualified Constants
Qualified constants look like this:
@@ -285,15 +287,16 @@ Qualified constants look like this:
Billing::Invoice
```
-`Billing::Invoice` is composed of two constants: `Billing`, in the first
-segment, is relative and is resolved using the algorithm of the previous
-section; `Invoice`, in the second segment, is qualified by `Billing` and we are
-going to see its resolution next. Let's call *parent* to that qualifying class
-or module object, that is, `Billing` in the example above:
+`Billing::Invoice` is composed of two constants: `Billing` is relative and is
+resolved using the algorithm of the previous section; `Invoice` is qualified by
+`Billing` and we are going to see its resolution next. Let's call *parent* to
+that qualifying class or module object, that is, `Billing` in the example above.
+The algorithm for qualified constants goes like this:
1. The constant is looked up in the parent and its ancestors.
-2. If the lookup fails, `const_missing` is invoked in the parent.
+2. If the lookup fails, `const_missing` is invoked in the parent. The default
+implementation of `const_missing` raises `NameError`, but it can be overridden.
As you see, this algorithm is simpler than the one for relative constants. In
particular, the nesting plays no role here, and modules are not special-cased,
@@ -338,12 +341,12 @@ still be "A::B".
The idea of a parent namespace is at the core of the autoloading algorithms
and helps explain and understand their motivation intuitively, but as you see
that metaphor leaks easily. Given an edge case to reason about, take always into
-account the by "parent namespace" the guide means exactly that specific string
+account that by "parent namespace" the guide means exactly that specific string
derivation.
### Loading Mechanism
-Rails autoloads files with `Kerne#load` when `config.cache_classes` is false,
+Rails autoloads files with `Kernel#load` when `config.cache_classes` is false,
the default in development mode, and with `Kernel#require` otherwise, the
default in production mode.
@@ -394,19 +397,18 @@ require 'erb'
```
Ruby looks for the file in the directories listed in `$LOAD_PATH`. That is, Ruby
-iterates over all its directories and for each one of them checks whether they
-have a file called "erb.rb", or "erb.so", or "erb.o", or "erb.dll". If it finds
-any of them, the interpreter loads it and ends the search. Otherwise, it tries
-again in the next directory of the list. If the list gets exhausted, `LoadError`
-is raised.
+iterates over all its directories and for each one of them checks whether it
+has a file called "erb.rb", "erb.so", "erb.o" or "erb.dll". If it finds one,
+the interpreter loads it and ends the search. Otherwise, it tries again in the
+next directory of the list. If the list gets exhausted, `LoadError` is raised.
We are going to cover how constant autoloading works in more detail later, but
-the idea is that when a constant like `Post` is hit and missing, if there's a
-*post.rb* file for example in *app/models* Rails is going to find it, evaluate
-it, and have `Post` defined as a side-effect.
+the idea is that when a constant like `Post` is hit and missing, if there is a
+*post.rb* file, for example in *app/models*, Rails will find it, evaluate it
+and allocate the class `Post` as a side-effect.
-Alright, Rails has a collection of directories similar to `$LOAD_PATH` in which
-to lookup that *post.rb*. That collection is called `autoload_paths` and by
+At this point, Rails has a collection of directories similar to `$LOAD_PATH` in
+which to look up *post.rb*. That collection is called `autoload_paths` and by
default it contains:
* All subdirectories of `app` in the application and engines. For example,
@@ -536,10 +538,10 @@ role.rb
modulus some additional directory lookups we are going to cover soon.
-INFO. 'Constant::Name'.underscore gives the relative path without extension of
+INFO. `'Constant::Name'.underscore` gives the relative path without extension of
the file name where `Constant::Name` is expected to be defined.
-Let's see how does Rails autoload the `Post` constant in the `PostsController`
+Let's see how Rails autoloads the `Post` constant in the `PostsController`
above assuming the application has a `Post` model defined in
`app/models/post.rb`.
@@ -582,7 +584,7 @@ file is loaded. If the file actually defines `Post` all is fine, otherwise
### Qualified References
When a qualified constant is missing Rails does not look for it in the parent
-namespaces. But there's a caveat: Unfortunately, when a constant is missing
+namespaces. But there's a caveat: unfortunately, when a constant is missing
Rails is not able to say if the trigger was a relative or qualified reference.
For example, consider
@@ -637,7 +639,7 @@ But since autoloading happens on demand, if the top-level `User` by chance was
not yet loaded then Rails has no way to know whether `Admin::User` should load it
or raise `NameError`.
-These kind of name conflicts are rare in practice, but in case there's one
+These kind of name conflicts are rare in practice but, in case there's one,
`require_dependency` provides a solution by making sure the constant needed to
trigger the heuristic is defined in the conflicting place.
@@ -773,7 +775,7 @@ the code.
Autoloading keeps track of autoloaded constants. Reloading is implemented by
removing them all from their respective classes and modules using
`Module#remove_const`. That way, when the code goes on, those constants are
-going to be unkown again, and files reloaded on demand.
+going to be unknown again, and files reloaded on demand.
INFO. This is an all-or-nothing operation, Rails does not attempt to reload only
what changed since dependencies between classes makes that really tricky.
@@ -793,7 +795,7 @@ the boot process. But constant autoloading in Rails is **not** implemented with
One possible implementation based on `Module#autoload` would be to walk the
application tree and issue `autoload` calls that map existing file names to
-their conventional contant name.
+their conventional constant name.
There are a number of reasons that prevent Rails from using that implementation.
@@ -840,16 +842,16 @@ class Admin::UsersController < ApplicationController
end
```
-If Ruby resolves `User` in the former case it checks whether there's a `User`
-constant in the `Admin` module. It does not in the latter case, because `Admin`
-does not belong to the nesting.
+To resolve `User` Ruby checks `Admin` in the former case, but it does not in
+the latter because it does not belong to the nesting. (See [Nesting](#nesting)
+and [Resolution Algorithms](#resolution- algorithms).)
Unfortunately Rails autoloading does not know the nesting in the spot where the
constant was missing and so it is not able to act as Ruby would. In particular,
-if `Admin::User` is autoloadable, it will get autoloaded in either case.
+`Admin::User` will get autoloaded in either case.
Albeit qualified constants with `class` and `module` keywords may technically
-work with autoloading in some cases, it is preferrable to use relative constants
+work with autoloading in some cases, it is preferable to use relative constants
instead:
```ruby
@@ -864,10 +866,10 @@ end
### Autoloading and STI
-STI (Single Table Inheritance) is a feature of Active Record that easies storing
-records that belong to a hierarchy of classes in one single table. The API of
-such models is aware of the hierarchy and encapsulates some common needs. For
-example, given these classes:
+Single Table Inheritance (STI) is a feature of Active Record that easies
+storing a hierarchy of models in one single table. The API of such models is
+aware of the hierarchy and encapsulates some common needs. For example, given
+these classes:
```ruby
# app/models/polygon.rb
@@ -884,37 +886,35 @@ end
```
`Triangle.create` creates a row that represents a triangle, and
-`Rectangle.create` creates a row that represents a rectangle. If `id` is the ID
-of an existing record, `Polygon.find(id)` returns an object of the correct type.
+`Rectangle.create` creates a row that represents a rectangle. If `id` is the
+ID of an existing record, `Polygon.find(id)` returns an object of the correct
+type.
-Methods that perform operations on collections are also aware of the hierarchy.
-For example, `Polygon.all` returns all the records of the table, because all
+Methods that operate on collections are also aware of the hierarchy. For
+example, `Polygon.all` returns all the records of the table, because all
rectangles and triangles are polygons. Active Record takes care of returning
instances of their corresponding class in the result set.
-When Active Record does this, it autoloads constants as needed. For example, if
-the class of `Polygon.first` is `Rectangle` and it has not yet been loaded,
-Active Record autoloads it and the record is fetched and correctly instantiated,
-transparently.
+Types are autoloaded as needed. For example, if `Polygon.first` is a rectangle
+and `Rectangle` has not yet been loaded, Active Record autoloads it and the
+record is correctly instantiated.
All good, but if instead of performing queries based on the root class we need
-to work on some subclass, then things get interesting.
+to work on some subclass, things get interesting.
While working with `Polygon` you do not need to be aware of all its descendants,
because anything in the table is by definition a polygon, but when working with
subclasses Active Record needs to be able to enumerate the types it is looking
for. Let’s see an example.
-`Rectangle.all` should return all the rectangles in the "polygons" table. In
-particular, no triangle should be fetched. To accomplish this, Active Record
-constraints the query to rows whose type column is “Rectangle”:
+`Rectangle.all` only loads rectangles by adding a type constraint to the query:
```sql
SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle")
```
-That works, but let’s introduce now a child of `Rectangle`:
+Let’s introduce now a subclass of `Rectangle`:
```ruby
# app/models/square.rb
@@ -922,16 +922,15 @@ class Square < Rectangle
end
```
-`Rectangle.all` should return rectangles **and** squares, the query should
-become
+`Rectangle.all` should now return rectangles **and** squares:
```sql
SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle", "Square")
```
-But there’s a subtle caveat here: How does Active Record know that the class
-`Square` exists at all?
+But there’s a caveat here: How does Active Record know that the class `Square`
+exists at all?
Even if the file `app/models/square.rb` exists and defines the `Square` class,
if no code yet used that class, `Rectangle.all` issues the query
@@ -941,8 +940,7 @@ SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle")
```
-That is not a bug in Active Record, as we saw above the query does include all
-*known* descendants of `Rectangle`.
+That is not a bug, the query includes all *known* descendants of `Rectangle`.
A way to ensure this works correctly regardless of the order of execution is to
load the leaves of the tree by hand at the bottom of the file that defines the
@@ -955,15 +953,14 @@ end
require_dependency ‘square’
```
-Only the leaves that are **at least grandchildren** have to be loaded that way.
-Direct subclasses do not need to be preloaded, and if the hierarchy is deeper
-intermediate superclasses will be autoloaded recursively from the bottom because
-their constant will appear in the definitions.
+Only the leaves that are **at least grandchildren** have to be loaded that
+way. Direct subclasses do not need to be preloaded and, if the hierarchy is
+deeper, intermediate classes will be autoloaded recursively from the bottom
+because their constant will appear in the class definitions as superclass.
### Autoloading and `require`
-Files defining constants that should be autoloaded should never be loaded with
-`require`:
+Files defining constants to be autoloaded should never be `require`d:
```ruby
require 'user' # DO NOT DO THIS
@@ -973,25 +970,21 @@ class UsersController < ApplicationController
end
```
-If some part of the application autoloads the `User` constant before, then the
-application will interpret `app/models/user.rb` twice in development mode.
+There are two possible gotchas here in development mode:
-As we saw before, in development mode autoloading uses `Kernel#load` by default.
-Since `load` does not store the name of the interpreted file in
-`$LOADED_FEATURES` (`$"`) `require` executes, again, `app/models/user.rb`.
+1. If `User` is autoloaded before reaching the `require`, `app/models/user.rb`
+runs again because `load` does not update `$LOADED_FEATURES`.
-On the other hand, if `app/controllers/users_controllers.rb` happens to be
-evaluated before `User` is autoloaded then dependencies won’t mark `User` as an
-autoloaded constant, and therefore changes to `app/models/user.rb` won’t be
-updated in development mode.
+2. If the `require` runs first Rails does not mark `User` as an autoloaded
+constant and changes to `app/models/user.rb` aren't reloaded.
-Just follow the flow and use constant autoloading always, never mix autoloading
-and `require`. As a last resort, if some file absolutely needs to load a certain
-file by hand use `require_dependency` to play nice with constant autoloading.
-This option is rarely needed in practice, though.
+Just follow the flow and use constant autoloading always, never mix
+autoloading and `require`. As a last resort, if some file absolutely needs to
+load a certain file use `require_dependency` to play nice with constant
+autoloading. This option is rarely needed in practice, though.
Of course, using `require` in autoloaded files to load ordinary 3rd party
-libraries is fine, and Rails is able to distinguish their constants, so they are
+libraries is fine, and Rails is able to distinguish their constants, they are
not marked as autoloaded.
### Autoloading and Initializers
@@ -999,24 +992,22 @@ not marked as autoloaded.
Consider this assignment in `config/initializers/set_auth_service.rb`:
```ruby
-AUTH_SERVICE = Rails.env.production? ? RealAuthService : MockedAuthService
+AUTH_SERVICE = if Rails.env.production?
+ RealAuthService
+else
+ MockedAuthService
+end
```
-The purpose of this setup would be that the application code uses always
-`AUTH_SERVICE` and that constant holds the proper class for the runtime
-environment. In development mode `MockedAuthService` gets autoloaded when the
-initializer is run. Let’s suppose we do some requests, change the implementation
-of `MockedAuthService`, and hit the application again. To our surprise the
-changes are not reflected. Why?
-
-As we saw earlier, Rails wipes autoloaded constants by removing them from their
-containers using `remove_const`. But the object the constant holds may remain
-stored somewhere else. Constant removal can’t do anything about that.
+The purpose of this setup would be that the application uses the class that
+corresponds to the environment via `AUTH_SERVICE`. In development mode
+`MockedAuthService` gets autoloaded when the initializer runs. Let’s suppose
+we do some requests, change its implementation, and hit the application again.
+To our surprise the changes are not reflected. Why?
-That is precisely the case in this example. `AUTH_SERVICE` stores the original
-class object which is perfectly functional regardless of the fact that there is
-no longer a constant in `Object` that matches its class name. The class object
-is independent of the constants it may or may not be stored in.
+As [we saw earlier](#constant-reloading), Rails removes autoloaded constants,
+but `AUTH_SERVICE` stores the original class object. Stale, non-reachable
+using the original constant, but perfectly functional.
The following code summarizes the situation:
@@ -1037,10 +1028,10 @@ C # => uninitialized constant C (NameError)
Because of that, it is not a good idea to autoload constants on application
initialization.
-In the case above we could for instance implement a dynamic access point that
-returns something that depends on the environment:
+In the case above we could implement a dynamic access point:
```ruby
+# app/models/auth_service.rb
class AuthService
if Rails.env.production?
def self.instance
@@ -1054,32 +1045,28 @@ class AuthService
end
```
-and have the application use `AuthService.instance` instead of `AUTH_SERVICE`.
-The code in that `AuthService` would be loaded on demand and be
-autoload-friendly.
+and have the application use `AuthService.instance` instead. `AuthService`
+would be loaded on demand and be autoload-friendly.
### `require_dependency` and Initializers
-As we saw before, `require_dependency` loads files in a autoloading-friendly
+As we saw before, `require_dependency` loads files in an autoloading-friendly
way. Normally, though, such a call does not make sense in an initializer.
-`require_dependency` provides a way to ensure a certain constant is defined at
-some point regardless of the execution path, and one could think about doing
-some calls in an initialzer to make sure certain constants are loaded upfront,
-for example as an attempt to address the gotcha with STIs.
+One could think about doing some [`require_dependency`](#require-dependency)
+calls in an initializer to make sure certain constants are loaded upfront, for
+example as an attempt to address the [gotcha with STIs](#autoloading-and-sti).
-Problem is, in development mode all autoloaded constants are wiped on a
-subsequent request as soon as there is some relevant change in the file system.
-When that happens the application is in the very same situation the initializer
-wanted to avoid!
+Problem is, in development mode [autoloaded constants are wiped](#constant-reloading)
+if there is any relevant change in the file system. If that happens then
+we are in the very same situation the initializer wanted to avoid!
Calls to `require_dependency` have to be strategically written in autoloaded
spots.
### When Constants aren't Missed
-Let’s imagine that a Rails application has an `Image` model, and a subclass
-`Hotel::Image`:
+Let's consider an `Image` model, superclass of `Hotel::Image`:
```ruby
# app/models/image.rb
@@ -1107,8 +1094,7 @@ end
```
The intention is to subclass `Hotel::Image`, but which is actually the
-superclass of `Hotel::Poster`? Well, it depends on the order of execution of the
-files:
+superclass of `Hotel::Poster`? Well, it depends on the order of execution:
1. If neither `app/models/image.rb` nor `app/models/hotel/image.rb` have been
loaded at that point, the superclass is `Hotel::Image` because Rails is told
@@ -1122,10 +1108,8 @@ is `Hotel::Image` because Ruby is able to resolve the constant. Good.
is `Image`. Gotcha!
The last scenario (3) may be surprising. Why isn't `Hotel::Image` autoloaded?
-
-Constant autoloading cannot happen at that point because Ruby is able to
-resolve `Image` as a top-level constant, in consequence autoloading is not
-triggered.
+Because Ruby is able to resolve `Image` as a top-level constant, so
+autoloading does not even get a chance.
Most of the time, these kind of ambiguities can be resolved using qualified
constants. In this case we would write
@@ -1137,19 +1121,17 @@ module Hotel
end
```
-That class definition now is robust. No matter which files have been
-previously loaded, we know for certain that the superclass is unambiguously
-set.
+That class definition now is robust.
-It is interesting to note here that fix works because `Hotel` is a module, and
+It is interesting to note here that the fix works because `Hotel` is a module, and
`Hotel::Image` won’t look for `Image` in `Object` as it would if `Hotel` was a
-class (because `Object` would be among its ancestors). If `Hotel` was class we
-would resort to loading `Hotel::Image` with `require_dependency`. Furthermore,
-with that solution the qualified name would no longer be necessary.
+class with `Object` in its ancestors. If `Hotel` was a class we would resort to
+loading `Hotel::Image` with `require_dependency`. Furthermore, with that
+solution the qualified name would no longer be necessary.
### Autoloading within Singleton Classes
-Let’s suppose we have these class definitions:
+Let's suppose we have these class definitions:
```ruby
# app/models/hotel/services.rb
@@ -1168,17 +1150,15 @@ module Hotel
end
```
-1. If `Hotel::Services` is known by the time `Hotel::GeoLocation` is being loaded,
-everything works because `Hotel` belongs to the nesting when the singleton class
-of `Hotel::GeoLocation` is opened, and thus Ruby itself is able to resolve the
-constant.
+If `Hotel::Services` is known by the time `app/models/hotel/geo_location.rb`
+is being loaded, `Services` is resolved by Ruby because `Hotel` belongs to the
+nesting when the singleton class of `Hotel::GeoLocation` is opened.
-2. But if `Hotel::Services` is not known and we rely on autoloading for the
-`Services` constant in `Hotel::GeoLocation`, Rails is not able to find
-`Hotel::Services`. The application raises `NameError`.
+But if `Hotel::Services` is not known, Rails is not able to autoload it, the
+application raises `NameError`.
The reason is that autoloading is triggered for the singleton class, which is
-anonymous, and as we [saw before](#generic-procedure), Rails only checks the
+anonymous, and as [we saw before](#generic-procedure), Rails only checks the
top-level namespace in that edge case.
An easy solution to this caveat is to qualify the constant:
@@ -1225,7 +1205,8 @@ c.user # surprisingly fine, User
c.user # NameError: uninitialized constant C::User
```
-because it detects a parent namespace already has the constant.
+because it detects a parent namespace already has the constant (see [Qualified
+References](#qualified-references).)
As with pure Ruby, within the body of a direct descendant of `BasicObject` use
always absolute constant paths:
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index ae16ad86cd..28fa61a964 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -904,7 +904,10 @@ You can also specify multiple videos to play by passing an array of videos to th
This will produce:
```erb
-<video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
+<video>
+ <source src="/videos/trailer.ogg">
+ <source src="/videos/movie.ogg">
+</video>
```
#### Linking to Audio Files with the `audio_tag`
diff --git a/guides/source/security.md b/guides/source/security.md
index b1c5b22338..b3869b1ba5 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -942,7 +942,7 @@ unless params[:token].nil?
end
```
-When `params[:token]` is one of: `[]`, `[nil]`, `[nil, nil, ...]` or
+When `params[:token]` is one of: `[nil]`, `[nil, nil, ...]` or
`['foo', nil]` it will bypass the test for `nil`, but `IS NULL` or
`IN ('foo', NULL)` where clauses still will be added to the SQL query.
@@ -953,9 +953,9 @@ request:
| JSON | Parameters |
|-----------------------------------|--------------------------|
| `{ "person": null }` | `{ :person => nil }` |
-| `{ "person": [] }` | `{ :person => nil }` |
-| `{ "person": [null] }` | `{ :person => nil }` |
-| `{ "person": [null, null, ...] }` | `{ :person => nil }` |
+| `{ "person": [] }` | `{ :person => [] }` |
+| `{ "person": [null] }` | `{ :person => [] }` |
+| `{ "person": [null, null, ...] }` | `{ :person => [] }` |
| `{ "person": ["foo", null] }` | `{ :person => ["foo"] }` |
It is possible to return to old behaviour and disable `deep_munge` configuring
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 518277a254..3db5b50ad6 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -111,7 +111,6 @@ module Rails
jbuilder_gemfile_entry,
sdoc_gemfile_entry,
psych_gemfile_entry,
- console_gemfile_entry,
@extra_entries].flatten.find_all(&@gem_filter)
end
@@ -267,15 +266,6 @@ module Rails
GemfileEntry.new('sdoc', '~> 0.4.0', comment, group: :doc)
end
- def console_gemfile_entry
- comment = 'Use Rails Console on the Browser'
- if options.dev? || options.edge?
- GemfileEntry.github 'web-console', 'rails/web-console', nil, comment
- else
- []
- end
- end
-
def coffee_gemfile_entry
comment = 'Use CoffeeScript for .coffee assets and views'
if options.dev? || options.edge?
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 7027312aa9..c5bd98a30e 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -32,7 +32,11 @@ group :development, :test do
<%- end -%>
# Access an IRB console on exception pages or by using <%%= console %> in views
+ <%- if options.dev? || options.edge? -%>
+ gem 'web-console', github: "rails/web-console"
+ <%- else -%>
gem 'web-console', '~> 2.0'
+ <%- end -%>
<%- if spring_install? %>
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index b7cbe04003..5f9f7ad50a 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -420,6 +420,24 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_gem 'web-console'
end
+ def test_web_console_with_dev_option
+ run_generator [destination_root, "--dev"]
+
+ assert_file "Gemfile" do |content|
+ assert_match(/gem 'web-console',\s+github: "rails\/web-console"/, content)
+ assert_no_match(/gem 'web-console', '~> 2.0'/, content)
+ end
+ end
+
+ def test_web_console_with_edge_option
+ run_generator [destination_root, "--edge"]
+
+ assert_file "Gemfile" do |content|
+ assert_match(/gem 'web-console',\s+github: "rails\/web-console"/, content)
+ assert_no_match(/gem 'web-console', '~> 2.0'/, content)
+ end
+ end
+
def test_spring
run_generator
assert_gem 'spring'