aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md31
-rw-r--r--actionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb1
-rw-r--r--actionpack/test/controller/mime/respond_with_test.rb15
-rw-r--r--actionpack/test/fixtures/respond_with/respond_with_additional_params.html.erb0
-rw-r--r--actionview/test/actionpack/controller/view_paths_test.rb (renamed from actionview/test/lib/controller/view_paths_test.rb)0
-rw-r--r--actionview/test/lib/controller/fake_controllers.rb35
-rw-r--r--activemodel/activemodel.gemspec2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb139
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb14
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_base.rb10
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_part.rb48
-rw-r--r--activerecord/lib/active_record/callbacks.rb5
-rw-r--r--activerecord/lib/active_record/inheritance.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb3
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb3
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb2
-rw-r--r--guides/source/action_mailer_basics.md2
-rw-r--r--guides/source/action_view_overview.md2
-rw-r--r--guides/source/active_record_validations.md2
-rw-r--r--guides/source/command_line.md11
-rw-r--r--guides/source/initialization.md22
-rw-r--r--guides/source/rails_on_rack.md6
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/lib/rails/configuration.rb4
-rw-r--r--railties/test/application/middleware_test.rb6
26 files changed, 195 insertions, 176 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index dc3e6d5c6a..7af9165605 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,13 +1,22 @@
+* Fixing repond_with working directly on the options hash
+ This fixes an issue where the respond_with worked directly with the given
+ options hash, so that if a user relied on it after calling respond_with,
+ the hash wouldn't be the same.
+
+ Fixes #12029.
+
+ *bluehotdog*
+
* Fix `ActionDispatch::RemoteIp::GetIp#calculate_ip` to only check for spoofing
attacks if both `HTTP_CLIENT_IP` and `HTTP_X_FORWARDED_FOR` are set.
- Fixes #10844
+ Fixes #10844.
*Tamir Duberstein*
* Strong parameters should permit nested number as key.
- Fixes #12293
+ Fixes #12293.
*kennyj*
@@ -23,14 +32,14 @@
* Fix an issue where router can't recognize downcased url encoding path.
- Fixes #12269
+ Fixes #12269.
*kennyj*
* Fix custom flash type definition. Misusage of the `_flash_types` class variable
caused an error when reloading controllers with custom flash types.
- Fixes #12057
+ Fixes #12057.
*Ricardo de Cillo*
@@ -51,21 +60,21 @@
* Fix an issue where :if and :unless controller action procs were being run
before checking for the correct action in the :only and :unless options.
- Fixes #11799
+ Fixes #11799.
*Nicholas Jakobsen*
* Fix an issue where `assert_dom_equal` and `assert_dom_not_equal` were
ignoring the passed failure message argument.
- Fixes #11751
+ Fixes #11751.
*Ryan McGeary*
* Allow REMOTE_ADDR, HTTP_HOST and HTTP_USER_AGENT to be overridden from
the environment passed into `ActionDispatch::TestRequest.new`.
- Fixes #11590
+ Fixes #11590.
*Andrew White*
@@ -80,7 +89,7 @@
* Skip routes pointing to a redirect or mounted application when generating urls
using an options hash as they aren't relevant and generate incorrect urls.
- Fixes #8018
+ Fixes #8018.
*Andrew White*
@@ -98,7 +107,7 @@
* Fix `ActionDispatch::ParamsParser#parse_formatted_parameters` to rewind body input stream on
parsing json params.
- Fixes #11345
+ Fixes #11345.
*Yuri Bol*, *Paul Nikitochkin*
@@ -131,7 +140,7 @@
was setting `request.formats` with an array containing a `nil` value, which
raised an error when setting the controller formats.
- Fixes #10965
+ Fixes #10965.
*Becker*
@@ -140,7 +149,7 @@
no `:to` present in the options hash so should only affect routes using the
shorthand syntax (i.e. endpoint is inferred from the path).
- Fixes #9856
+ Fixes #9856.
*Yves Senn*, *Andrew White*
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index db7b56f47e..3b0d094f4f 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -73,7 +73,7 @@ module ActionController
# <input type="text" name="post[address]" value="hyacintvej">
#
# A request stemming from a form holding these inputs will include <tt>{ "post" => { "name" => "david", "address" => "hyacintvej" } }</tt>.
- # If the address input had been named \"post[address][street]", the params would have included
+ # If the address input had been named <tt>post[address][street]</tt>, the params would have included
# <tt>{ "post" => { "address" => { "street" => "hyacintvej" } } }</tt>. There's no limit to the depth of the nesting.
#
# == Sessions
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 66dabd821f..a072fce1a1 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -326,6 +326,7 @@ module ActionController #:nodoc:
if collector = retrieve_collector_from_mimes(&block)
options = resources.size == 1 ? {} : resources.extract_options!
+ options = options.clone
options[:default_response] = collector.response
(options.delete(:responder) || self.class.responder).call(self, resources, options)
end
diff --git a/actionpack/test/controller/mime/respond_with_test.rb b/actionpack/test/controller/mime/respond_with_test.rb
index 76af9e3414..a70592fa1b 100644
--- a/actionpack/test/controller/mime/respond_with_test.rb
+++ b/actionpack/test/controller/mime/respond_with_test.rb
@@ -65,7 +65,17 @@ class RespondWithController < ActionController::Base
respond_with(resource, :responder => responder)
end
+ def respond_with_additional_params
+ @params = RespondWithController.params
+ respond_with({:result => resource}, @params)
+ end
+
protected
+ def self.params
+ {
+ :foo => 'bar'
+ }
+ end
def resource
Customer.new("david", request.delete? ? nil : 13)
@@ -145,6 +155,11 @@ class RespondWithControllerTest < ActionController::TestCase
Mime::Type.unregister(:mobile)
end
+ def test_respond_with_shouldnt_modify_original_hash
+ get :respond_with_additional_params
+ assert_equal RespondWithController.params, assigns(:params)
+ end
+
def test_using_resource
@request.accept = "application/xml"
get :using_resource
diff --git a/actionpack/test/fixtures/respond_with/respond_with_additional_params.html.erb b/actionpack/test/fixtures/respond_with/respond_with_additional_params.html.erb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/actionpack/test/fixtures/respond_with/respond_with_additional_params.html.erb
diff --git a/actionview/test/lib/controller/view_paths_test.rb b/actionview/test/actionpack/controller/view_paths_test.rb
index c6e7a523b9..c6e7a523b9 100644
--- a/actionview/test/lib/controller/view_paths_test.rb
+++ b/actionview/test/actionpack/controller/view_paths_test.rb
diff --git a/actionview/test/lib/controller/fake_controllers.rb b/actionview/test/lib/controller/fake_controllers.rb
deleted file mode 100644
index 1a2863b689..0000000000
--- a/actionview/test/lib/controller/fake_controllers.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class ContentController < ActionController::Base; end
-
-module Admin
- class AccountsController < ActionController::Base; end
- class PostsController < ActionController::Base; end
- class StuffController < ActionController::Base; end
- class UserController < ActionController::Base; end
- class UsersController < ActionController::Base; end
-end
-
-module Api
- class UsersController < ActionController::Base; end
- class ProductsController < ActionController::Base; end
-end
-
-class AccountController < ActionController::Base; end
-class ArchiveController < ActionController::Base; end
-class ArticlesController < ActionController::Base; end
-class BarController < ActionController::Base; end
-class BlogController < ActionController::Base; end
-class BooksController < ActionController::Base; end
-class CarsController < ActionController::Base; end
-class CcController < ActionController::Base; end
-class CController < ActionController::Base; end
-class FooController < ActionController::Base; end
-class GeocodeController < ActionController::Base; end
-class NewsController < ActionController::Base; end
-class NotesController < ActionController::Base; end
-class PagesController < ActionController::Base; end
-class PeopleController < ActionController::Base; end
-class PostsController < ActionController::Base; end
-class SubpathBooksController < ActionController::Base; end
-class SymbolsController < ActionController::Base; end
-class UserController < ActionController::Base; end
-class UsersController < ActionController::Base; end
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index 51655fe3da..11e755649c 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
s.name = 'activemodel'
s.version = version
s.summary = 'A toolkit for building modeling frameworks (part of Rails).'
- s.description = 'A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, observers, serialization, internationalization, and testing.'
+ s.description = 'A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, serialization, internationalization, and testing.'
s.required_ruby_version = '>= 1.9.3'
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index f12d5c49b5..2fdb1970e1 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -4,7 +4,7 @@ module ActiveRecord
autoload :JoinBase, 'active_record/associations/join_dependency/join_base'
autoload :JoinAssociation, 'active_record/associations/join_dependency/join_association'
- attr_reader :join_parts, :alias_tracker, :base_klass
+ attr_reader :alias_tracker, :base_klass, :join_root
def self.make_tree(associations)
hash = {}
@@ -54,43 +54,43 @@ module ActiveRecord
def initialize(base, associations, joins)
@base_klass = base
@table_joins = joins
- @join_parts = [JoinBase.new(base)]
+ @join_root = JoinBase.new(base)
@alias_tracker = AliasTracker.new(base.connection, joins)
@alias_tracker.aliased_name_for(base.table_name) # Updates the count for base.table_name to 1
tree = self.class.make_tree associations
- build tree, join_parts.last, Arel::InnerJoin
+ build tree, @join_root, Arel::InnerJoin
end
def graft(*associations)
- join_assocs = join_associations
- base = join_base
-
- associations.reject { |association|
- join_assocs.detect { |a| association == a }
- }.each { |association|
- join_part = find_parent_part(association.parent) || base
- type = association.join_type
- find_or_build_scalar association.reflection, join_part, type
+ associations.reject { |join_node|
+ find_node join_node
+ }.each { |join_node|
+ parent = find_node(join_node.parent) || join_root
+ reflection = join_node.reflection
+ type = join_node.join_type
+
+ next if parent.children.find { |j| j.reflection == reflection }
+ build_scalar reflection, parent, type
}
self
end
- def join_associations
- join_parts.drop 1
- end
-
def reflections
- join_associations.map(&:reflection)
+ join_root.drop(1).map!(&:reflection)
end
def join_relation(relation)
- join_associations.inject(relation) do |rel,association|
+ join_root.inject(relation) do |rel,association|
association.join_relation(rel)
end
end
+ def join_constraints
+ join_root.flat_map(&:join_constraints)
+ end
+
def columns
- join_parts.collect { |join_part|
+ join_root.collect { |join_part|
table = join_part.aliased_table
join_part.column_names_with_alias.collect{ |column_name, aliased_name|
table[column_name].as Arel.sql(aliased_name)
@@ -99,16 +99,16 @@ module ActiveRecord
end
def instantiate(result_set)
- primary_key = join_base.aliased_primary_key
+ primary_key = join_root.aliased_primary_key
parents = {}
type_caster = result_set.column_type primary_key
- assoc = associations
+ assoc = join_root.children
records = result_set.map { |row_hash|
primary_id = type_caster.type_cast row_hash[primary_key]
- parent = parents[primary_id] ||= join_base.instantiate(row_hash)
- construct(parent, assoc, join_associations, row_hash, result_set)
+ parent = parents[primary_id] ||= join_root.instantiate(row_hash)
+ construct(parent, assoc, row_hash, result_set)
parent
}.uniq
@@ -118,30 +118,29 @@ module ActiveRecord
private
- def associations
- join_associations.each_with_object({}) do |assoc, tree|
- cache_joined_association assoc, tree
- end
- end
+ def find_node(target_node)
+ stack = target_node.parents << target_node
+
+ left = [join_root]
+ right = stack.shift
- def find_parent_part(parent)
- join_parts.detect do |join_part|
- case parent
- when JoinBase
- parent.base_klass == join_part.base_klass
+ loop {
+ match = left.find { |l| l.match? right }
+
+ if match
+ return match if stack.empty?
+
+ left = match.children
+ right = stack.shift
else
- parent == join_part
+ return nil
end
- end
- end
-
- def join_base
- join_parts.first
+ }
end
def remove_duplicate_results!(base, records, associations)
- associations.each_key do |name|
- reflection = base.reflect_on_association(name)
+ associations.each do |node|
+ reflection = base.reflect_on_association(node.name)
remove_uniq_by_reflection(reflection, records)
parent_records = []
@@ -156,26 +155,13 @@ module ActiveRecord
end
unless parent_records.empty?
- remove_duplicate_results!(reflection.klass, parent_records, associations[name])
+ remove_duplicate_results!(reflection.klass, parent_records, node.children)
end
end
end
- def cache_joined_association(association, tree)
- associations = []
- parent = association.parent
- while parent != join_base
- associations.unshift(parent.reflection.name)
- parent = parent.parent
- end
- ref = associations.inject(tree) do |cache,key|
- cache[key]
- end
- ref[association.reflection.name] ||= {}
- end
-
def find_reflection(klass, name)
- klass.reflect_on_association(name.intern) or
+ klass.reflect_on_association(name) or
raise ConfigurationError, "Association named '#{ name }' was not found on #{ klass.name }; perhaps you misspelled it?"
end
@@ -183,23 +169,14 @@ module ActiveRecord
associations.each do |name, right|
reflection = find_reflection parent.base_klass, name
join_association = build_join_association reflection, parent, join_type
- @join_parts << join_association
+ parent.children << join_association
build right, join_association, join_type
end
end
- def find_or_build_scalar(reflection, parent, join_type)
- unless join_association = find_join_association(reflection, parent)
- join_association = build_join_association(reflection, parent, join_type)
- @join_parts << join_association
- end
- join_association
- end
-
- def find_join_association(reflection, parent)
- join_associations.detect { |j|
- j.reflection == reflection && j.parent == parent
- }
+ def build_scalar(reflection, parent, join_type)
+ join_association = build_join_association(reflection, parent, join_type)
+ parent.children << join_association
end
def remove_uniq_by_reflection(reflection, records)
@@ -215,30 +192,16 @@ module ActiveRecord
raise EagerLoadPolymorphicError.new(reflection)
end
- JoinAssociation.new(reflection, join_parts.length, parent, join_type, alias_tracker)
+ JoinAssociation.new(reflection, join_root.to_a.length, parent, join_type, alias_tracker)
end
- def construct(parent, associations, join_parts, row, rs)
- associations.sort_by { |k,_| k.to_s }.each do |association_name, assoc|
- association = construct_scalar(parent, association_name, join_parts, row, rs)
- construct(association, assoc, join_parts, row, rs) if association
+ def construct(parent, nodes, row, rs)
+ nodes.sort_by { |k| k.name }.each do |node|
+ association = construct_association(parent, node, row, rs)
+ construct(association, node.children, row, rs) if association
end
end
- def construct_scalar(parent, associations, join_parts, row, rs)
- name = associations.to_s
-
- join_part = join_parts.detect { |j|
- j.reflection.name.to_s == name &&
- j.parent_table_name == parent.class.table_name
- }
-
- raise(ConfigurationError, "No such association") unless join_part
-
- join_parts.delete(join_part)
- construct_association(parent, join_part, row, rs)
- end
-
def construct_association(record, join_part, row, rs)
caster = rs.column_type(join_part.parent.aliased_primary_key)
row_id = caster.type_cast row[join_part.parent.aliased_primary_key]
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index f6a04ef9f1..fe915c7730 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -9,10 +9,6 @@ module ActiveRecord
# The reflection of the association represented
attr_reader :reflection
- # A JoinBase instance representing the active record we are joining onto.
- # (So in Author.has_many :posts, the Author would be that base record.)
- attr_reader :parent
-
# What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
attr_accessor :join_type
@@ -25,11 +21,10 @@ module ActiveRecord
delegate :options, :through_reflection, :source_reflection, :chain, :to => :reflection
def initialize(reflection, index, parent, join_type, alias_tracker)
- super(reflection.klass)
+ super(reflection.klass, parent)
@reflection = reflection
@alias_tracker = alias_tracker
- @parent = parent
@join_type = join_type
@aliased_prefix = "t#{ index }"
@tables = construct_tables.reverse
@@ -38,10 +33,9 @@ module ActiveRecord
def parent_table_name; parent.table_name; end
alias :alias_suffix :parent_table_name
- def ==(other)
- other.class == self.class &&
- other.reflection == reflection &&
- other.parent == parent
+ def match?(other)
+ return true if self == other
+ super && reflection == other.reflection
end
def join_constraints
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_base.rb b/activerecord/lib/active_record/associations/join_dependency/join_base.rb
index c689d06594..48de12bcd5 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_base.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_base.rb
@@ -4,9 +4,13 @@ module ActiveRecord
module Associations
class JoinDependency # :nodoc:
class JoinBase < JoinPart # :nodoc:
- def ==(other)
- other.class == self.class &&
- other.base_klass == base_klass
+ def initialize(klass)
+ super(klass, nil)
+ end
+
+ def match?(other)
+ return true if self == other
+ super && base_klass == other.base_klass
end
def aliased_prefix
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
index 2b6034ca9d..d536eaf613 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -8,25 +8,61 @@ module ActiveRecord
# operations (for example a has_and_belongs_to_many JoinAssociation would result in
# two; one for the join table and one for the target table).
class JoinPart # :nodoc:
+ include Enumerable
+
+ # A JoinBase instance representing the active record we are joining onto.
+ # (So in Author.has_many :posts, the Author would be that base record.)
+ attr_reader :parent
+
# The Active Record class which this join part is associated 'about'; for a JoinBase
# this is the actual base model, for a JoinAssociation this is the target model of the
# association.
- attr_reader :base_klass
+ attr_reader :base_klass, :children
delegate :table_name, :column_names, :primary_key, :arel_engine, :to => :base_klass
- def initialize(base_klass)
+ def initialize(base_klass, parent)
@base_klass = base_klass
+ @parent = parent
@cached_record = {}
@column_names_with_alias = nil
+ @children = []
end
- def aliased_table
- Arel::Nodes::TableAlias.new table, aliased_table_name
+ def join_constraints; []; end
+ def join_relation(rel); rel; end
+
+ def name
+ reflection.name
end
- def ==(other)
- raise NotImplementedError
+ def match?(other)
+ self.class == other.class
+ end
+
+ def parents
+ parents = []
+ node = parent
+ while node
+ parents.unshift node
+ node = node.parent
+ end
+ parents
+ end
+
+ def each
+ yield self
+ iter = lambda { |list|
+ list.each { |item|
+ yield item
+ iter.call item.children
+ }
+ }
+ iter.call children
+ end
+
+ def aliased_table
+ Arel::Nodes::TableAlias.new table, aliased_table_name
end
# An Arel::Table for the active_record
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index e4c484d64b..128a9377c1 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -23,11 +23,14 @@ module ActiveRecord
# Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
# <tt>after_rollback</tt>.
#
+ # Additionally, an <tt>after_touch</tt> callback is triggered whenever an
+ # object is touched.
+ #
# Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
# is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
# are instantiated as well.
#
- # That's a total of twelve callbacks, which gives you immense power to react and prepare for each state in the
+ # There are nineteen callbacks in total, which give you immense power to react and prepare for each state in the
# Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
# except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
#
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index e826762def..7e1e120288 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -160,7 +160,7 @@ module ActiveRecord
end
def type_condition(table = arel_table)
- sti_column = table[inheritance_column.to_sym]
+ sti_column = table[inheritance_column]
sti_names = ([self] + descendants).map { |model| model.sti_name }
sti_column.in(sti_names)
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 267aa28058..a73a140ef1 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -401,7 +401,8 @@ module ActiveRecord
end
# Saves the record with the updated_at/on attributes set to the current time.
- # Please note that no validation is performed and no callbacks are executed.
+ # Please note that no validation is performed and only the +after_touch+
+ # callback is executed.
# If an attribute name is passed, that attribute is updated along with
# updated_at/on attributes.
#
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 9fcb6db726..e1efc6a189 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -952,8 +952,7 @@ module ActiveRecord
join_dependency.graft(*stashed_association_joins)
- joins = join_dependency.join_associations.map!(&:join_constraints)
- joins.flatten!
+ joins = join_dependency.join_constraints
joins.each { |join| manager.from(join) }
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 5299e4e17e..3b61b91d62 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -785,7 +785,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
sarah = Person.create!(:first_name => 'Sarah', :primary_contact_id => people(:susan).id, :gender => 'F', :number1_fan_id => 1)
john = Person.create!(:first_name => 'John', :primary_contact_id => sarah.id, :gender => 'M', :number1_fan_id => 1)
assert_equal sarah.agents, [john]
- assert_equal people(:susan).agents.map(&:agents).flatten, people(:susan).agents_of_agents
+ assert_equal people(:susan).agents.flat_map(&:agents), people(:susan).agents_of_agents
end
def test_associate_existing_with_nonstandard_primary_key_on_belongs_to
diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md
index 93a2b89ede..61fd762304 100644
--- a/guides/source/action_mailer_basics.md
+++ b/guides/source/action_mailer_basics.md
@@ -105,7 +105,7 @@ will be the template used for the email, formatted in HTML:
<h1>Welcome to example.com, <%= @user.name %></h1>
<p>
You have successfully signed up to example.com,
- your username is: <%= @user.login %>.<br/>
+ your username is: <%= @user.login %>.<br>
</p>
<p>
To login to the site, just follow this link: <%= @url %>.
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index 5cda104138..94aa0f8502 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -68,7 +68,7 @@ Consider the following loop for names:
```html+erb
<h1>Names of all the people</h1>
<% @people.each do |person| %>
- Name: <%= person.name %><br/>
+ Name: <%= person.name %><br>
<% end %>
```
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index 0b2f0a47fa..339612ebc5 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -783,7 +783,7 @@ end
Person.new.valid? # => ActiveModel::StrictValidationFailed: Name can't be blank
```
-There is also an ability to pass custom exception to `:strict` option
+There is also an ability to pass custom exception to `:strict` option.
```ruby
class Person < ActiveRecord::Base
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index 51ff921d7b..1b0b93c3bc 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -379,12 +379,13 @@ About your application's environment
Ruby version 1.9.3 (x86_64-linux)
RubyGems version 1.3.6
Rack version 1.3
-Rails version 4.0.0
+Rails version 4.1.0
JavaScript Runtime Node.js (V8)
-Active Record version 4.0.0
-Action Pack version 4.0.0
-Action Mailer version 4.0.0
-Active Support version 4.0.0
+Active Record version 4.1.0
+Action Pack version 4.1.0
+Action View version 4.1.0
+Action Mailer version 4.1.0
+Active Support version 4.1.0
Middleware Rack::Sendfile, ActionDispatch::Static, Rack::Lock, #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007ffd131a7c88>, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::RemoteIp, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::Migration::CheckPending, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::Head, Rack::ConditionalGet, Rack::ETag
Application root /home/foobar/commandsapp
Environment development
diff --git a/guides/source/initialization.md b/guides/source/initialization.md
index 91d12b4432..fe6b1ad906 100644
--- a/guides/source/initialization.md
+++ b/guides/source/initialization.md
@@ -468,14 +468,24 @@ def initialize!(group=:default) #:nodoc:
end
```
-As you can see, you can only initialize an app once. This is also where the initializers are run.
+As you can see, you can only initialize an app once. The initializers are run through
+the `run_initializers` method which is defined in `railties/lib/rails/initializable.rb`
-TODO: review this
+```ruby
+def run_initializers(group=:default, *args)
+ return if instance_variable_defined?(:@ran)
+ initializers.tsort_each do |initializer|
+ initializer.run(*args) if initializer.belongs_to?(group)
+ end
+ @ran = true
+end
+```
-The initializers code itself is tricky. What Rails is doing here is it
-traverses all the class ancestors looking for an `initializers` method,
-sorting them and running them. For example, the `Engine` class will make
-all the engines available by providing the `initializers` method.
+The run_initializers code itself is tricky. What Rails is doing here is
+traversing all the class ancestors looking for those that respond to an
+`initializers` method. It then sorts the ancestors by name, and runs them.
+For example, the `Engine` class will make all the engines available by
+providing an `initializers` method on them.
The `Rails::Application` class, as defined in `railties/lib/rails/application.rb`
defines `bootstrap`, `railtie`, and `finisher` initializers. The `bootstrap` initializers
diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md
index 642c70fd9d..d53e0cd2bd 100644
--- a/guides/source/rails_on_rack.md
+++ b/guides/source/rails_on_rack.md
@@ -225,9 +225,13 @@ config.middleware.delete "Rack::MethodOverride"
Much of Action Controller's functionality is implemented as Middlewares. The following list explains the purpose of each of them:
+ **`Rack::Sendfile`**
+
+* Sets server specific X-Sendfile header. Configure this via `config.action_dispatch.x_sendfile_header` option.
+
**`ActionDispatch::Static`**
-* Used to serve static assets. Disabled if `config.serve_static_assets` is true.
+* Used to serve static assets. Disabled if `config.serve_static_assets` is `false`.
**`Rack::Lock`**
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index a4babbe8c3..4e6bf899af 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Expose MiddlewareStack#unshift to environment configuration.
+
+ *Ben Pickles*
+
* Include `web-console` into newly generated applications' Gemfile.
*Genadi Samokovarov*
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index c694513960..f5d7dede66 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -59,6 +59,10 @@ module Rails
@operations << [__method__, args, block]
end
+ def unshift(*args, &block)
+ @operations << [__method__, args, block]
+ end
+
def merge_into(other) #:nodoc:
@operations.each do |operation, args, block|
other.send(operation, *args, &block)
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index 31a35a09bb..20d1d76d78 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -144,6 +144,12 @@ module ApplicationTests
assert_equal "Rack::Config", middleware.second
end
+ test 'unshift middleware' do
+ add_to_config 'config.middleware.unshift Rack::Config'
+ boot!
+ assert_equal 'Rack::Config', middleware.first
+ end
+
test "Rails.cache does not respond to middleware" do
add_to_config "config.cache_store = :memory_store"
boot!