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/controller/filters_test.rb20
-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.rb9
-rw-r--r--activesupport/lib/active_support/callbacks.rb9
-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--activesupport/test/callbacks_test.rb48
-rw-r--r--guides/CHANGELOG.md4
-rw-r--r--guides/source/4_2_release_notes.md27
-rw-r--r--guides/source/action_controller_overview.md4
-rw-r--r--guides/source/active_record_basics.md2
-rw-r--r--guides/source/active_record_migrations.md6
-rw-r--r--guides/source/active_record_querying.md37
-rw-r--r--guides/source/association_basics.md46
-rw-r--r--guides/source/constant_autoloading_and_reloading.md575
-rw-r--r--guides/source/getting_started.md16
-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/lib/rails/tasks/statistics.rake6
-rw-r--r--railties/test/generators/app_generator_test.rb18
29 files changed, 591 insertions, 350 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/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index 38533dbf23..829729eb1b 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -504,7 +504,6 @@ class FilterTest < ActionController::TestCase
def non_yielding_action
@filters << "it didn't yield"
- @filter_return_value
end
def action_three
@@ -528,32 +527,15 @@ class FilterTest < ActionController::TestCase
end
end
- def test_non_yielding_around_actions_not_returning_false_do_not_raise
+ def test_non_yielding_around_actions_do_not_raise
controller = NonYieldingAroundFilterController.new
- controller.instance_variable_set "@filter_return_value", true
assert_nothing_raised do
test_process(controller, "index")
end
end
- def test_non_yielding_around_actions_returning_false_do_not_raise
- controller = NonYieldingAroundFilterController.new
- controller.instance_variable_set "@filter_return_value", false
- assert_nothing_raised do
- test_process(controller, "index")
- end
- end
-
- def test_after_actions_are_not_run_if_around_action_returns_false
- controller = NonYieldingAroundFilterController.new
- controller.instance_variable_set "@filter_return_value", false
- test_process(controller, "index")
- assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
- end
-
def test_after_actions_are_not_run_if_around_action_does_not_yield
controller = NonYieldingAroundFilterController.new
- controller.instance_variable_set "@filter_return_value", true
test_process(controller, "index")
assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
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..d037447567 100644
--- a/actionview/test/template/tag_helper_test.rb
+++ b/actionview/test/template/tag_helper_test.rb
@@ -50,6 +50,11 @@ class TagHelperTest < ActionView::TestCase
assert_dom_equal "<div>Hello world!</div>", buffer
end
+ def test_content_tag_with_block_in_erb_containing_non_displayed_erb
+ buffer = render_erb("<%= content_tag(:p) do %><% 1 %><% end %>")
+ assert_dom_equal "<p></p>", buffer
+ end
+
def test_content_tag_with_block_and_options_in_erb
buffer = render_erb("<%= content_tag(:div, :class => 'green') do %>Hello world!<% end %>")
assert_dom_equal %(<div class="green">Hello world!</div>), buffer
@@ -65,8 +70,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/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 24c702b602..95dbc9a0cb 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -659,16 +659,17 @@ module ActiveSupport
# ===== Options
#
# * <tt>:terminator</tt> - Determines when a before filter will halt the
- # callback chain, preventing following callbacks from being called and
- # the event from being triggered. This should be a lambda to be executed.
+ # callback chain, preventing following before and around callbacks from
+ # being called and the event from being triggered.
+ # This should be a lambda to be executed.
# The current object and the return result of the callback will be called
# with the lambda.
#
# define_callbacks :validate, terminator: ->(target, result) { result == false }
#
# In this example, if any before validate callbacks returns +false+,
- # other callbacks are not executed. Defaults to +false+, meaning no value
- # halts the chain.
+ # any successive before and around callback is not executed.
+ # Defaults to +false+, meaning no value halts the chain.
#
# * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
# callbacks should be terminated by the <tt>:terminator</tt> option. By
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/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 32c2dfdfc0..d19e5fd6e7 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -49,7 +49,7 @@ module CallbacksTest
def self.before(model)
model.history << [:before_save, :class]
end
-
+
def self.after(model)
model.history << [:after_save, :class]
end
@@ -501,21 +501,20 @@ module CallbacksTest
end
end
- class CallbackTerminator
+ class AbstractCallbackTerminator
include ActiveSupport::Callbacks
- define_callbacks :save, :terminator => ->(_,result) { result == :halt }
-
- set_callback :save, :before, :first
- set_callback :save, :before, :second
- set_callback :save, :around, :around_it
- set_callback :save, :before, :third
- set_callback :save, :after, :first
- set_callback :save, :around, :around_it
- set_callback :save, :after, :second
- set_callback :save, :around, :around_it
- set_callback :save, :after, :third
-
+ def self.set_save_callbacks
+ set_callback :save, :before, :first
+ set_callback :save, :before, :second
+ set_callback :save, :around, :around_it
+ set_callback :save, :before, :third
+ set_callback :save, :after, :first
+ set_callback :save, :around, :around_it
+ set_callback :save, :after, :second
+ set_callback :save, :around, :around_it
+ set_callback :save, :after, :third
+ end
attr_reader :history, :saved, :halted
def initialize
@@ -552,6 +551,17 @@ module CallbacksTest
end
end
+ class CallbackTerminator < AbstractCallbackTerminator
+ define_callbacks :save, terminator: ->(_,result) { result == :halt }
+ set_save_callbacks
+ end
+
+ class CallbackTerminatorSkippingAfterCallbacks < AbstractCallbackTerminator
+ define_callbacks :save, terminator: ->(_,result) { result == :halt },
+ skip_after_callbacks_if_terminated: true
+ set_save_callbacks
+ end
+
class CallbackObject
def before(caller)
caller.record << "before"
@@ -688,7 +698,7 @@ module CallbacksTest
end
class CallbackTerminatorTest < ActiveSupport::TestCase
- def test_termination
+ def test_termination_skips_following_before_and_around_callbacks
terminator = CallbackTerminator.new
terminator.save
assert_equal ["first", "second", "third", "second", "first"], terminator.history
@@ -707,6 +717,14 @@ module CallbacksTest
end
end
+ class CallbackTerminatorSkippingAfterCallbacksTest < ActiveSupport::TestCase
+ def test_termination_skips_after_callbacks
+ terminator = CallbackTerminatorSkippingAfterCallbacks.new
+ terminator.save
+ assert_equal ["first", "second"], terminator.history
+ end
+ end
+
class HyphenatedKeyTest < ActiveSupport::TestCase
def test_save
obj = HyphenatedCallbacks.new
diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md
index afaa404ac1..5a65f1355e 100644
--- a/guides/CHANGELOG.md
+++ b/guides/CHANGELOG.md
@@ -1 +1,5 @@
+* New section in Active Record Querying: Understanding The Method Chaining
+
+ *andreynering*
+
Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/guides/CHANGELOG.md) for previous changes.
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index 1e9107a8c6..d8700539c4 100644
--- a/guides/source/4_2_release_notes.md
+++ b/guides/source/4_2_release_notes.md
@@ -509,6 +509,17 @@ Please refer to the [Changelog][action-pack] for detailed changes.
serving assets from your Rails server in production.
([Pull Request](https://github.com/rails/rails/pull/16466))
+* When calling the `process` helpers in an integration test the path needs to have
+ a leading slash. Previously you could omit it but that was a byproduct of the
+ implementation and not an intentional feature, e.g.:
+
+ ```ruby
+ test "list all posts" do
+ get "/posts"
+ assert_response :success
+ end
+ ```
+
Action View
-----------
@@ -544,17 +555,6 @@ Please refer to the [Changelog][action-view] for detailed changes.
* Placeholder I18n follows the same convention as `label` I18n.
([Pull Request](https://github.com/rails/rails/pull/16438))
-* When calling the `process` helpers in an integration test the path needs to have
- a leading slash. Previously you could omit it but that was a byproduct of the
- implementation and not an intentional feature, e.g.:
-
- ```ruby
-   test "list all posts" do
-     get "/posts"
-     assert_response :success 
- end
- ```
-
Action Mailer
-------------
@@ -640,6 +640,10 @@ Please refer to the [Changelog][active-record] for detailed changes.
`Relation` for performing queries and updates is the preferred API.
([Commit](https://github.com/rails/rails/commit/d5902c9e))
+* Deprecated `add_timestamps` and `t.timestamps` without passing the `:null`
+ option. The default of `null: true` will change in Rails 5 to `null: false`.
+ ([Pull Request](https://github.com/rails/rails/pull/16481))
+
* Deprecated `Reflection#source_macro` without replacement as it is no longer
needed in Active Record.
([Pull Request](https://github.com/rails/rails/pull/16373))
@@ -824,6 +828,7 @@ Please refer to the [Changelog][active-support] for detailed changes.
`module Foo; extend ActiveSupport::Concern; end` boilerplate.
([Commit](https://github.com/rails/rails/commit/b16c36e688970df2f96f793a759365b248b582ad))
+* New [guide](constant_autoloading_and_reloading.html) about constant autoloading and reloading.
Credits
-------
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_basics.md b/guides/source/active_record_basics.md
index bd074d0055..ef86531eef 100644
--- a/guides/source/active_record_basics.md
+++ b/guides/source/active_record_basics.md
@@ -358,7 +358,7 @@ class CreatePublications < ActiveRecord::Migration
t.string :publisher_type
t.boolean :single_issue
- t.timestamps
+ t.timestamps null: false
end
add_index :publications, :publication_type_id
end
diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md
index 1a41fc8b4c..e76a57e164 100644
--- a/guides/source/active_record_migrations.md
+++ b/guides/source/active_record_migrations.md
@@ -39,7 +39,7 @@ class CreateProducts < ActiveRecord::Migration
t.string :name
t.text :description
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -285,7 +285,7 @@ class CreateProducts < ActiveRecord::Migration
t.string :name
t.text :description
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -826,7 +826,7 @@ class CreateProducts < ActiveRecord::Migration
create_table :products do |t|
t.string :name
t.text :description
- t.timestamps
+ t.timestamps null: false
end
end
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index e1a465c64f..f6fbc29707 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -9,6 +9,7 @@ After reading this guide, you will know:
* How to specify the order, retrieved attributes, grouping, and other properties of the found records.
* How to use eager loading to reduce the number of database queries needed for data retrieval.
* How to use dynamic finders methods.
+* How to use method chaining to use multiple ActiveRecord methods together.
* How to check for the existence of particular records.
* How to perform various calculations on Active Record models.
* How to run EXPLAIN on relations.
@@ -1327,10 +1328,44 @@ You can specify an exclamation point (`!`) on the end of the dynamic finders to
If you want to find both by name and locked, you can chain these finders together by simply typing "`and`" between the fields. For example, `Client.find_by_first_name_and_locked("Ryan", true)`.
+Understanding The Method Chaining
+---------------------------------
+
+The ActiveRecord pattern implements [Method Chaining](http://en.wikipedia.org/wiki/Method_chaining).
+This allow us to use multiple ActiveRecord methods in a simple and straightforward way.
+
+You can chain a method in a sentence when the previous method called returns `ActiveRecord::Relation`,
+like `all`, `where`, and `joins`. Methods that returns a instance of a single object
+(see [Retrieving a Single Object Section](#retrieving-a-single-object)) have to be be the last
+in the sentence.
+
+This guide won't cover all the possibilities, just a few as example.
+
+### Retrieving filtered data from multiple tables
+
+```ruby
+Person
+ .select('people.id, people.name, comments.text')
+ .joins(:comments)
+ .where('comments.create_at > ?', 1.week.ago)
+```
+
+### Retrieving specific data from multiple tables
+
+```ruby
+Person
+ .select('people.id, people.name, companies.name')
+ .joins(:company)
+ .find_by('people.name' => 'John') # this should be the last
+```
+
+NOTE: Remember that, if `find_by` return more than one registry, it will take just the first
+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/association_basics.md b/guides/source/association_basics.md
index a12f5638e3..5c05f0c4b7 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -101,13 +101,13 @@ class CreateOrders < ActiveRecord::Migration
def change
create_table :customers do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :orders do |t|
t.belongs_to :customer, index: true
t.datetime :order_date
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -132,13 +132,13 @@ class CreateSuppliers < ActiveRecord::Migration
def change
create_table :suppliers do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :accounts do |t|
t.belongs_to :supplier, index: true
t.string :account_number
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -165,13 +165,13 @@ class CreateCustomers < ActiveRecord::Migration
def change
create_table :customers do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :orders do |t|
t.belongs_to :customer, index:true
t.datetime :order_date
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -207,19 +207,19 @@ class CreateAppointments < ActiveRecord::Migration
def change
create_table :physicians do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :patients do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :appointments do |t|
t.belongs_to :physician, index: true
t.belongs_to :patient, index: true
t.datetime :appointment_date
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -291,19 +291,19 @@ class CreateAccountHistories < ActiveRecord::Migration
def change
create_table :suppliers do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :accounts do |t|
t.belongs_to :supplier, index: true
t.string :account_number
- t.timestamps
+ t.timestamps null: false
end
create_table :account_histories do |t|
t.belongs_to :account, index: true
t.integer :credit_rating
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -332,12 +332,12 @@ class CreateAssembliesAndParts < ActiveRecord::Migration
def change
create_table :assemblies do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :parts do |t|
t.string :part_number
- t.timestamps
+ t.timestamps null: false
end
create_table :assemblies_parts, id: false do |t|
@@ -371,13 +371,13 @@ class CreateSuppliers < ActiveRecord::Migration
def change
create_table :suppliers do |t|
t.string :name
- t.timestamps
+ t.timestamps null: false
end
create_table :accounts do |t|
t.integer :supplier_id
t.string :account_number
- t.timestamps
+ t.timestamps null: false
end
add_index :accounts, :supplier_id
@@ -455,7 +455,7 @@ class CreatePictures < ActiveRecord::Migration
t.string :name
t.integer :imageable_id
t.string :imageable_type
- t.timestamps
+ t.timestamps null: false
end
add_index :pictures, :imageable_id
@@ -471,7 +471,7 @@ class CreatePictures < ActiveRecord::Migration
create_table :pictures do |t|
t.string :name
t.references :imageable, polymorphic: true, index: true
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -501,7 +501,7 @@ class CreateEmployees < ActiveRecord::Migration
def change
create_table :employees do |t|
t.references :manager, index: true
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -879,10 +879,12 @@ class Order < ActiveRecord::Base
belongs_to :customer, counter_cache: :count_of_orders
end
class Customer < ActiveRecord::Base
- has_many :orders
+ has_many :orders, counter_cache: :count_of_orders
end
```
+NOTE: You only need to specify the :counter_cache option on the "has_many side" of the association when using a custom name for the counter cache.
+
Counter cache columns are added to the containing model's list of read-only attributes through `attr_readonly`.
##### `:dependent`
@@ -1495,6 +1497,7 @@ The `has_many` association supports these options:
* `:as`
* `:autosave`
* `:class_name`
+* `:counter_cache`
* `:dependent`
* `:foreign_key`
* `:inverse_of`
@@ -1522,6 +1525,9 @@ class Customer < ActiveRecord::Base
end
```
+##### `:counter_cache`
+This option can be used to configure a custom named `:counter_cache`. You only need this option when you customized the name of your `:counter_cache` on the [belongs_to association](#options-for-belongs-to).
+
##### `:dependent`
Controls what happens to the associated objects when their owner is destroyed:
diff --git a/guides/source/constant_autoloading_and_reloading.md b/guides/source/constant_autoloading_and_reloading.md
index de75b4fab7..5f435ddbd8 100644
--- a/guides/source/constant_autoloading_and_reloading.md
+++ b/guides/source/constant_autoloading_and_reloading.md
@@ -6,15 +6,10 @@ This guide documents how constant autoloading and reloading works.
After reading this guide, you will know:
* Key aspects of Ruby constants
-
* What is `autoload_paths`
-
* How constant autoloading works
-
* What is `require_dependency`
-
* How constant reloading works
-
* Solutions to common autoloading gotchas
--------------------------------------------------------------------------------
@@ -23,11 +18,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'
@@ -41,7 +34,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
@@ -49,7 +42,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
@@ -62,96 +55,101 @@ end
This guide documents how that works.
-Vocabulary
-----------
+Constants Refresher
+-------------------
-### Parent Namespaces
+While constants are trivial in most programming languages, they are a rich
+topic in Ruby.
-Given a string with a constant path we define its *parent namespace* to be the
-string that results from removing its rightmost segment.
+It is beyond the scope of this guide to document Ruby constants, but we are
+nevertheless going to highlight a few key topics. Truly grasping the following
+sections is instrumental to understanding constant autoloading and reloading.
-For example, the parent namespace of the string "A::B::C" is the string "A::B",
-the parent namespace of "A::B" is "A", and the parent namespace of "A" is "".
+### Nesting
-The interpretation of a parent namespace when thinking about classes and modules
-is tricky though. Let's consider a module M named "A::B":
+Class and module definitions can be nested to create namespaces:
-* The parent namespace, "A", may not reflect nesting at a given spot.
+```ruby
+module XML
+ class SAXParser
+ # (1)
+ end
+end
+```
-* The constant `A` may no longer exist, some code could have removed it from
-`Object`.
+The *nesting* at any given place is the collection of enclosing nested class and
+module objects outwards. For example, in the previous example, the nesting at
+(1) is
-* If `A` exists, the class or module that was originally in `A` may not be there
-anymore. For example, if after a constant removal there was another constant
-assignment there would generally be a different object in there.
+```ruby
+[XML::SAXParser, XML]
+```
-* In such case, it could even happen that the reassigned `A` held a new class or
-module called also "A"!
+It is important to understand that the nesting is composed of class and module
+*objects*, it has nothing to do with the constants used to access them, and is
+also unrelated to their names.
-* In the previous scenarios M would no longer be reachable through `A::B` but
-the module object itself could still be alive somewhere and its name would
-still be "A::B".
+For instance, while this definition is similar to the previous one:
-The idea of a parent namespace it's at the core of the autoloading algorithms
-and helps explain and understand intuitively their motivation, 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
-derivation.
+```ruby
+class XML::SAXParser
+ # (2)
+end
+```
-### Loading Mechanism
+the nesting in (2) is different, `XML` does not belong to it:
-Rails autoloads files with `Kerne#load` when `config.cache_classes` is false,
-the default in development mode, and with `Kernel#require` otherwise, the
-default in production mode.
+```ruby
+[XML::SAXParser]
+```
-`Kernel#load` allows Rails to execute files more than once if [constant
-reloading](#constant-reloading) is enabled.
-
-This guide uses the word "load" freely to mean a given file is interpreted, but
-the actual mechanism can be `Kernel#load` or `Kernel#require` depending on that
-flag.
+We can see in this example that the name of a class or module that belongs to a
+certain nesting does not necessarily correlate with the namespaces at the spot.
+Even more, they are totally independent, take for instance
-Autoloading Availability
-------------------------
+```ruby
+module X::Y
+ module A::B
+ # (3)
+ end
+end
+```
-Rails is always able to autoload provided its environment is in place. For
-example the `runner` command autoloads:
+The nesting in (3) consists of two module objects:
-```
-$ bin/rails runner 'p User.column_names'
-["id", "email", "created_at", "updated_at"]
+```ruby
+[A::B, X::Y]
```
-The console autoloads, the test suite autoloads, and of course the application
-autoloads.
+So, it not only doesn't end in `A`, which does not even belong to the nesting,
+but it also contains `X::Y`, which is independent from `A::B`.
-By default, Rails eager loads the application files when it boots in production
-mode, so most of the autoloading going on in development does not happen. But
-autoloading may still be triggered because at top-level constants not yet loaded
-may be referenced.
+The nesting is an internal stack maintained by the interpreter, and it gets
+modified according to these rules:
-For example, given
+* The class object following a `class` keyword gets pushed when its body is
+executed, and popped after it.
-```ruby
-class BeachHouse < House
-end
-```
+* The module object following a `module` keyword gets pushed when its body is
+executed, and popped after it.
-if `House` is still unknown when `app/models/beach_house.rb` is being eager
-loaded, Rails autoloads 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.
-Constants Refresher
--------------------
+* 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.
-While constants are trivial in most programming languages, they are a rich
-topic in 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.
-It is beyond the scope of this guide to document Ruby constants, but we are
-nevertheless going to highlight a couple of key topics. Truly grasping the
-following two sections is instrumental to understanding constant autoloading and
-reloading.
+The nesting at any given place can be inspected with `Module.nesting`.
### Class and Module Definitions are Constant Assignments
@@ -179,7 +177,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
@@ -194,8 +192,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
@@ -203,7 +201,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
@@ -222,7 +220,7 @@ constants on the fly.
### Constants are Stored in Modules
Constants belong to modules in a very literal sense. Classes and modules have
-a constant table, think of it as a hash table.
+a constant table; think of it as a hash table.
Let's analyze an example to really understand what that means. While in a
casual setting some abuses of language are customary, the exposition is going
@@ -238,21 +236,150 @@ end
First, when the `module` keyword is processed the interpreter creates a new
entry in the constant table of the class object stored in the `Object` constant.
-Said entry associates the string "Colors" to a newly created module object.
+Said entry associates the name "Colors" to a newly created module object.
Furthermore, the interpreter sets the name of the new module object to be the
string "Colors".
Later, when the body of the module definition is interpreted, a new entry is
created in the constant table of the module object stored in the `Colors`
-constant. That entry maps the string "RED" to the string "0xff0000".
+constant. That entry maps the name "RED" to the string "0xff0000".
In particular, `Colors::RED` is totally unrelated to any other `RED` constant
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 as strings, and value objects
-assiociated to them in constant tables.
+class and module objects, constant names, and value objects associated to them
+in constant tables.
+
+### 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.
+
+Without getting too much into the details, the resolution algorithm for relative
+constant references goes like this:
+
+1. If the nesting is not empty the constant is looked up in its elements and in
+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. 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
+
+Qualified constants look like this:
+
+```ruby
+Billing::Invoice
+```
+
+`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. 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,
+if neither they nor their ancestors have the constants, `Object` is **not**
+checked.
+
+Rails autoloading **does not emulate this algorithm**, but its starting point is
+the name of the constant to be autoloaded, and the parent. See more in
+[Qualified References](#qualified-references).
+
+
+Vocabulary
+----------
+
+### Parent Namespaces
+
+Given a string with a constant path we define its *parent namespace* to be the
+string that results from removing its rightmost segment.
+
+For example, the parent namespace of the string "A::B::C" is the string "A::B",
+the parent namespace of "A::B" is "A", and the parent namespace of "A" is "".
+
+The interpretation of a parent namespace when thinking about classes and modules
+is tricky though. Let's consider a module M named "A::B":
+
+* The parent namespace, "A", may not reflect nesting at a given spot.
+
+* The constant `A` may no longer exist, some code could have removed it from
+`Object`.
+
+* If `A` exists, the class or module that was originally in `A` may not be there
+anymore. For example, if after a constant removal there was another constant
+assignment there would generally be a different object in there.
+
+* In such case, it could even happen that the reassigned `A` held a new class or
+module called also "A"!
+
+* In the previous scenarios M would no longer be reachable through `A::B` but
+the module object itself could still be alive somewhere and its name would
+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 that by "parent namespace" the guide means exactly that specific string
+derivation.
+
+### Loading Mechanism
+
+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.
+
+`Kernel#load` allows Rails to execute files more than once if [constant
+reloading](#constant-reloading) is enabled.
+
+This guide uses the word "load" freely to mean a given file is interpreted, but
+the actual mechanism can be `Kernel#load` or `Kernel#require` depending on that
+flag.
+
+
+Autoloading Availability
+------------------------
+
+Rails is always able to autoload provided its environment is in place. For
+example the `runner` command autoloads:
+
+```
+$ bin/rails runner 'p User.column_names'
+["id", "email", "created_at", "updated_at"]
+```
+
+The console autoloads, the test suite autoloads, and of course the application
+autoloads.
+
+By default, Rails eager loads the application files when it boots in production
+mode, so most of the autoloading going on in development does not happen. But
+autoloading may still be triggered during eager loading.
+
+For example, given
+
+```ruby
+class BeachHouse < House
+end
+```
+
+if `House` is still unknown when `app/models/beach_house.rb` is being eager
+loaded, Rails autoloads it.
autoload_paths
@@ -273,11 +400,11 @@ 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
+`post.rb` file for example in `app/models` Rails is going to find it, evaluate
it, and have `Post` defined 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
+to lookup that `post.rb`. That collection is called `autoload_paths` and by
default it contains:
* All subdirectories of `app` in the application and engines. For example,
@@ -322,7 +449,7 @@ Autoloading Algorithms
### Relative References
-A relative constant may appear in several places, for example, in
+A relative constant reference may appear in several places, for example, in
```ruby
class PostsController < ApplicationController
@@ -332,7 +459,7 @@ class PostsController < ApplicationController
end
```
-all three constants are relative.
+all three constant references are relative.
#### Constants after the `class` and `module` Keywords
@@ -349,8 +476,8 @@ define the controller.
#### Top-Level Constants
-On the contrary, if `ApplicationController` is unknown, an autoload is going to
-be attempted by Rails.
+On the contrary, if `ApplicationController` is unknown, the constant is
+considered missing and an autoload is going to be attempted by Rails.
In order to load `ApplicationController`, Rails iterates over `autoload_paths`.
First checks if `app/assets/application_controller.rb` exists. If it does not,
@@ -378,7 +505,7 @@ for namespaces comes into play.
The basic idea is that given
-```
+```ruby
module Admin
class BaseController < ApplicationController
@@all_roles = Role.all
@@ -407,10 +534,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`.
@@ -425,7 +552,7 @@ test/mailers/previews/posts_controller/post.rb
```
Since the lookup is exhausted without success, a similar search for a directory
-is performed, we are going to see why in the next section:
+is performed, we are going to see why in the [next section](#automatic-modules):
```
app/assets/posts_controller/post
@@ -453,13 +580,13 @@ 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
-Rails is not able to say if the trigger was a relative or qualified reference.
+namespaces. But there is a caveat: When a constant is missing, Rails is
+unable to tell if the trigger was a relative reference or a qualified one.
For example, consider
```ruby
-module Amin
+module Admin
User
end
```
@@ -490,7 +617,7 @@ and the `User` constant is already present in `Object`, it is not possible that
the situation is
```ruby
-module Amin
+module Admin
User
end
```
@@ -500,17 +627,17 @@ been triggered in the first place. Thus, Rails assumes a qualified reference and
considers the file `admin/user.rb` and directory `admin/user` to be the only
valid options.
-In practice this works quite well as long as the nesting matches all parent
+In practice, this works quite well as long as the nesting matches all parent
namespaces respectively and the constants that make the rule apply are known at
that time.
-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 `Amin::User` should load it
-or raise `NameError`.
+However, autoloading happens on demand. If by chance the top-level `User` 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
-`require_dependency` provides a solution by making sure the constant needed to
-trigger the heuristic is defined in the conflicting place.
+Naming conflicts of this kind are rare in practice, but if one occurs,
+`require_dependency` provides a solution by ensuring that the constant needed
+to trigger the heuristic is defined in the conflicting place.
### Automatic Modules
@@ -524,17 +651,25 @@ Suppose an application has a backoffice whose controllers are stored in
If `autoload_paths` has a file called `admin.rb` Rails is going to load that
one, but if there's no such file and a directory called `admin` is found, Rails
-creates an empty module and assigns it to the constant `Admin` on the fly.
+creates an empty module and assigns it to the `Admin` constant on the fly.
### Generic Procedure
-The procedure to autoload constant `C` in an arbitrary situation is:
+Relative references are reported to be missing in the cref where they were hit,
+and qualified references are reported to be missing in their parent. (See
+[Resolution Algorithm for Relative
+Constants](#resolution-algorithm-for-relative-constants) at the beginning of
+this guide for the definition of *cref*, and [Resolution Algorithm for Qualified
+Constants](#resolution-algorithm-for-qualified-constants) for the definition of
+*parent*.)
+
+The procedure to autoload constant `C` in an arbitrary situation is as follows:
```
-if the nesting is empty
+if the class or module in which C is missing is Object
let ns = ''
else
- let M = nesting.first
+ let M = the class or module in which C is missing
if M is anonymous
let ns = ''
@@ -636,13 +771,46 @@ 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.
Instead, everything is wiped.
+Module#autoload isn't Involved
+------------------------------
+
+`Module#autoload` provides a lazy way to load constants that is fully integrated
+with the Ruby constant lookup algorithms, dynamic constant API, etc. It is quite
+transparent.
+
+Rails internals make extensive use of it to defer as much work as possible from
+the boot process. But constant autoloading in Rails is **not** implemented with
+`Module#autoload`.
+
+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 constant name.
+
+There are a number of reasons that prevent Rails from using that implementation.
+
+For example, `Module#autoload` is only capable of loading files using `require`,
+so reloading would not be possible. Not only that, it uses an internal `require`
+which is not `Kernel#require`.
+
+Then, it provides no way to remove declarations in case a file is deleted. If a
+constant gets removed with `Module#remove_const` its `autoload` is not triggered
+again. Also, it doesn't support qualified names, so files with namespaces should
+be interpreted during the walk tree to install their own `autoload` calls, but
+those files could have constant references not yet configured.
+
+An implementation based on `Module#autoload` would be awesome but, as you see,
+at least as of today it is not possible. Constant autoloading in Rails is
+implemented with `Module#const_missing`, and that's why it has its own contract,
+documented in this guide.
+
+
Common Gotchas
--------------
@@ -670,16 +838,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 autoloading does not know the nesting in the spot where the
+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
@@ -694,10 +862,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
@@ -714,37 +882,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
@@ -752,16 +918,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
@@ -771,8 +936,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
@@ -785,15 +949,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** need to be loaded this
+way. Direct subclasses do not need to be preloaded. 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
@@ -803,25 +966,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 though in practice.
+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
@@ -829,24 +988,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:
@@ -867,10 +1024,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
@@ -884,32 +1041,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
@@ -937,8 +1090,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
@@ -952,10 +1104,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
@@ -967,19 +1117,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
@@ -998,18 +1146,16 @@ module Hotel
end
```
-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.
-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, Rails only checks the top-level namespace in
-that edge case.
+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:
@@ -1049,13 +1195,14 @@ first time the `user` method is invoked. You only get the exception if the
`User` constant is known at that point, in particular in a *second* call to
`user`:
-```
+```ruby
c = C.new
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/getting_started.md b/guides/source/getting_started.md
index c2a0fde54e..31f78ba11c 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -90,18 +90,18 @@ current version of Ruby installed:
TIP: A number of tools exist to help you quickly install Ruby and Ruby
on Rails on your system. Windows users can use [Rails Installer](http://railsinstaller.org),
while Mac OS X users can use [Tokaido](https://github.com/tokaido/tokaidoapp).
+For more installation methods for most Operating Systems take a look at
+[ruby-lang.org](https://www.ruby-lang.org/en/documentation/installation/).
```bash
$ ruby -v
ruby 2.0.0p353
```
-If you don't have Ruby installed have a look at
-[ruby-lang.org](https://www.ruby-lang.org/en/installation/) for possible ways to
-install Ruby on your platform.
-
-Many popular UNIX-like OSes ship with an acceptable version of SQLite3. Windows
-users and others can find installation instructions at the [SQLite3 website](https://www.sqlite.org).
+Many popular UNIX-like OSes ship with an acceptable version of SQLite3.
+On Windows, if you installed Rails through Rails Installer, you
+already have SQLite installed. Others can find installation instructions
+at the [SQLite3 website](https://www.sqlite.org).
Verify that it is correctly installed and in your PATH:
```bash
@@ -677,7 +677,7 @@ class CreateArticles < ActiveRecord::Migration
t.string :title
t.text :text
- t.timestamps
+ t.timestamps null: false
end
end
end
@@ -1539,7 +1539,7 @@ class CreateComments < ActiveRecord::Migration
# this line adds an integer column called `article_id`.
t.references :article, index: true
- t.timestamps
+ t.timestamps null: false
end
end
end
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/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake
index 4f09ded31d..ba6168e208 100644
--- a/railties/lib/rails/tasks/statistics.rake
+++ b/railties/lib/rails/tasks/statistics.rake
@@ -1,6 +1,6 @@
-# while having global constant is not good,
-# many 3rd party tools depend on it, like rspec-rails, cucumber-rails, etc
-# so if will be removed - deprecation warning is needed
+# While global constants are bad, many 3rd party tools depend on this one (e.g
+# rspec-rails & cucumber-rails). So a deprecation warning is needed if we want
+# to remove it.
STATS_DIRECTORIES = [
%w(Controllers app/controllers),
%w(Helpers app/helpers),
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'