diff options
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! |