diff options
21 files changed, 85 insertions, 86 deletions
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 9d6b6c7914..50f2c71737 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -449,7 +449,7 @@ class BaseTest < ActiveSupport::TestCase assert_equal("Format with any!", email.parts[1].body.encoded) end - test 'test' do + test 'explicit without specifying format with format.any' do error = assert_raises(ArgumentError) do BaseMailer.explicit_without_specifying_format_with_any.parts end diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index fbbaa1a887..f16c851456 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -33,6 +33,9 @@ module ActionController self.session = session self.session_options = TestSession::DEFAULT_OPTIONS + @custom_param_parsers = { + Mime::XML => lambda { |raw_post| Hash.from_xml(raw_post)['hash'] } + } end def query_string=(string) @@ -74,26 +77,18 @@ module ActionController set_header k, 'application/x-www-form-urlencoded' end - # FIXME: setting `request_parametes` is normally handled by the - # params parser middleware, and we should remove this roundtripping - # when we switch to caling `call` on the controller - case content_mime_type.to_sym when nil raise "Unknown Content-Type: #{content_type}" when :json data = ActiveSupport::JSON.encode(non_path_parameters) - params = ActiveSupport::JSON.decode(data).with_indifferent_access - self.request_parameters = params when :xml data = non_path_parameters.to_xml - params = Hash.from_xml(data)['hash'] - self.request_parameters = params when :url_encoded_form data = non_path_parameters.to_query else + @custom_param_parsers[content_mime_type] = ->(_) { non_path_parameters } data = non_path_parameters.to_query - self.request_parameters = non_path_parameters end end @@ -136,6 +131,12 @@ module ActionController "multipart/form-data; boundary=#{Rack::Test::MULTIPART_BOUNDARY}" end end.new + + private + + def params_parsers + super.merge @custom_param_parsers + end end class LiveTestResponse < Live::Response diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 3c9f8cd9e4..27fadb708e 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -3,6 +3,20 @@ module ActionDispatch module Parameters PARAMETERS_KEY = 'action_dispatch.request.path_parameters' + DEFAULT_PARSERS = { + Mime::JSON => lambda { |raw_post| + data = ActiveSupport::JSON.decode(raw_post) + data.is_a?(Hash) ? data : {:_json => data} + } + } + + def self.included(klass) + class << klass + attr_accessor :parameter_parsers + end + + klass.parameter_parsers = DEFAULT_PARSERS + end # Returns both GET and POST \parameters in a single hash. def parameters params = get_header("action_dispatch.request.parameters") @@ -31,6 +45,27 @@ module ActionDispatch def path_parameters get_header(PARAMETERS_KEY) || {} end + + private + + def parse_formatted_parameters(parsers) + return yield if content_length.zero? + + strategy = parsers.fetch(content_mime_type) { return yield } + + begin + strategy.call(raw_post) + rescue => e # JSON or Ruby code block errors + my_logger = logger || ActiveSupport::Logger.new($stderr) + my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}" + + raise ParamsParser::ParseError.new(e.message, e) + end + end + + def params_parsers + ActionDispatch::Request.parameter_parsers + end end end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index b2566c4820..eaa7e88b34 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -348,8 +348,14 @@ module ActionDispatch # Override Rack's POST method to support indifferent access def POST fetch_header("action_dispatch.request.request_parameters") do - self.request_parameters = Request::Utils.normalize_encode_params(super || {}) + pr = parse_formatted_parameters(params_parsers) do |params| + super || {} + end + self.request_parameters = Request::Utils.normalize_encode_params(pr) end + rescue ParamsParser::ParseError # one of the parse strategies blew up + self.request_parameters = Request::Utils.normalize_encode_params(super || {}) + raise rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e raise ActionController::BadRequest.new(:request, e) end diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 9cde9c9b98..18af0a583a 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -18,48 +18,13 @@ module ActionDispatch end end - DEFAULT_PARSERS = { - Mime::JSON => lambda { |raw_post| - data = ActiveSupport::JSON.decode(raw_post) - data = {:_json => data} unless data.is_a?(Hash) - Request::Utils.normalize_encode_params(data) - } - } - # Create a new +ParamsParser+ middleware instance. # # The +parsers+ argument can take Hash of parsers where key is identifying # content mime type, and value is a lambda that is going to process data. - def initialize(app, parsers = {}) - @app, @parsers = app, DEFAULT_PARSERS.merge(parsers) + def self.new(app, parsers = {}) + ActionDispatch::Request.parameter_parsers = ActionDispatch::Request::DEFAULT_PARSERS.merge(parsers) + app end - - def call(env) - request = Request.new(env) - - parse_formatted_parameters(request, @parsers) do |params| - request.request_parameters = params - end - - @app.call(env) - end - - private - def parse_formatted_parameters(request, parsers) - return if request.content_length.zero? - - strategy = parsers.fetch(request.content_mime_type) { return nil } - - yield strategy.call(request.raw_post) - - rescue => e # JSON or Ruby code block errors - logger(request).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}" - - raise ParseError.new(e.message, e) - end - - def logger(request) - request.logger || ActiveSupport::Logger.new($stderr) - end end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 3c498960e4..ef7aab72c6 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -104,7 +104,6 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public") middleware.use ActionDispatch::DebugExceptions middleware.use ActionDispatch::Callbacks - middleware.use ActionDispatch::ParamsParser middleware.use ActionDispatch::Cookies middleware.use ActionDispatch::Flash middleware.use Rack::Head diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index b26f037c36..8b37c9599e 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -97,24 +97,28 @@ class WebServiceTest < ActionDispatch::IntegrationTest end def test_parsing_json_doesnot_rescue_exception - with_test_route_set do - with_params_parsers Mime::JSON => Proc.new { |data| raise Interrupt } do - assert_raises(Interrupt) do - post "/", - params: '{"title":"JSON"}}', - headers: { 'CONTENT_TYPE' => 'application/json' } - end + req = Class.new(ActionDispatch::Request) do + def params_parsers + { Mime::JSON => Proc.new { |data| raise Interrupt } } end + + def content_length; get_header('rack.input').length; end + end.new({ 'rack.input' => StringIO.new('{"title":"JSON"}}'), 'CONTENT_TYPE' => 'application/json' }) + + assert_raises(Interrupt) do + req.request_parameters end end private def with_params_parsers(parsers = {}) old_session = @integration_session - @app = ActionDispatch::ParamsParser.new(app.routes, parsers) + original_parsers = ActionDispatch::Request.parameter_parsers + ActionDispatch::Request.parameter_parsers = original_parsers.merge parsers reset! yield ensure + ActionDispatch::Request.parameter_parsers = original_parsers @integration_session = old_session end diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index 12870acaa6..2354e91822 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -151,7 +151,6 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public") middleware.use ActionDispatch::DebugExceptions middleware.use ActionDispatch::Callbacks - middleware.use ActionDispatch::ParamsParser middleware.use ActionDispatch::Cookies middleware.use ActionDispatch::Flash middleware.use Rack::Head diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 07d5e7d38e..bbf2a51a0e 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -45,7 +45,7 @@ module ActiveRecord write_attribute_with_type_cast(attr_name, value, true) end - def raw_write_attribute(attr_name, value) + def raw_write_attribute(attr_name, value) # :nodoc: write_attribute_with_type_cast(attr_name, value, false) end diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb index 0c8ff79237..d5bb11deed 100644 --- a/activesupport/lib/active_support/core_ext/numeric/conversions.rb +++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb @@ -41,7 +41,7 @@ class Numeric # 1000.to_s(:percentage, delimiter: '.', separator: ',') # => 1.000,000% # 302.24398923423.to_s(:percentage, precision: 5) # => 302.24399% # 1000.to_s(:percentage, locale: :fr) # => 1 000,000% - # 100.to_s(:percentage, format: '%n %') # => 100 % + # 100.to_s(:percentage, format: '%n %') # => 100.000 % # # Delimited: # 12345678.to_s(:delimited) # => 12,345,678 @@ -78,7 +78,7 @@ class Numeric # 1234567.to_s(:human_size, precision: 2) # => 1.2 MB # 483989.to_s(:human_size, precision: 2) # => 470 KB # 1234567.to_s(:human_size, precision: 2, separator: ',') # => 1,2 MB - # 1234567890123.to_s(:human_size, precision: 5) # => "1.1229 TB" + # 1234567890123.to_s(:human_size, precision: 5) # => "1.1228 TB" # 524288000.to_s(:human_size, precision: 5) # => "500 MB" # # Human-friendly format: diff --git a/activesupport/lib/active_support/core_ext/securerandom.rb b/activesupport/lib/active_support/core_ext/securerandom.rb index 6cdbea1f37..98cf7430f7 100644 --- a/activesupport/lib/active_support/core_ext/securerandom.rb +++ b/activesupport/lib/active_support/core_ext/securerandom.rb @@ -10,8 +10,8 @@ module SecureRandom # # The result may contain alphanumeric characters except 0, O, I and l # - # p SecureRandom.base58 #=> "4kUgL2pdQMSCQtjE" - # p SecureRandom.base58(24) #=> "77TMHrHJFvFDwodq8w7Ev2m7" + # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE" + # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7" # def self.base58(n = 16) SecureRandom.random_bytes(n).unpack("C*").map do |byte| diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index dadac7fb54..7f88c13dc0 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -242,7 +242,7 @@ end >> person = Person.new >> person.valid? ->> person.errors.details[:name] #=> [{error: :blank}] +>> person.errors.details[:name] # => [{error: :blank}] ``` Using `details` with custom validators is covered in the [Working with diff --git a/guides/source/api_app.md b/guides/source/api_app.md index 28727a51bd..feaaff166a 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -194,7 +194,6 @@ An API application comes with the following middlewares by default: - `ActionDispatch::RemoteIp` - `ActionDispatch::Reloader` - `ActionDispatch::Callbacks` -- `ActionDispatch::ParamsParser` - `Rack::Head` - `Rack::ConditionalGet` - `Rack::ETag` @@ -292,9 +291,9 @@ instructions in the `Rack::Sendfile` documentation. NOTE: The `Rack::Sendfile` middleware is always outside of the `Rack::Lock` mutex, even in single-threaded applications. -### Using ActionDispatch::ParamsParser +### Using ActionDispatch::Request -`ActionDispatch::ParamsParser` will take parameters from the client in the JSON +`ActionDispatch::Request#params` will take parameters from the client in the JSON format and make them available in your controller inside `params`. To use this, your client will need to make a request with JSON-encoded parameters @@ -313,7 +312,7 @@ jQuery.ajax({ }); ``` -`ActionDispatch::ParamsParser` will see the `Content-Type` and your parameters +`ActionDispatch::Request` will see the `Content-Type` and your parameters will be: ```ruby diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index a4feff798d..526bf768cc 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -239,7 +239,7 @@ You can quickly test the RDoc output with the following command: ``` $ echo "+:to_param+" | rdoc --pipe -#=> <p><code>:to_param</code></p> +# => <p><code>:to_param</code></p> ``` ### Regular Font diff --git a/guides/source/command_line.md b/guides/source/command_line.md index cd265331d6..e85f9fc9c6 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -412,7 +412,7 @@ Ruby version 2.2.2 (x86_64-linux) RubyGems version 2.4.6 Rack version 1.6 JavaScript Runtime Node.js (V8) -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 +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, Rack::Head, Rack::ConditionalGet, Rack::ETag Application root /home/foobar/commandsapp Environment development Database adapter sqlite3 diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 5e72b96787..0dd99cf8e9 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -214,7 +214,6 @@ Every Rails application comes with a standard set of middleware which it uses in * `ActionDispatch::Cookies` sets cookies for the request. * `ActionDispatch::Session::CookieStore` is responsible for storing the session in cookies. An alternate middleware can be used for this by changing the `config.action_controller.session_store` to an alternate value. Additionally, options passed to this can be configured by using `config.action_controller.session_options`. * `ActionDispatch::Flash` sets up the `flash` keys. Only available if `config.action_controller.session_store` is set to a value. -* `ActionDispatch::ParamsParser` parses out parameters from the request into `params`. * `Rack::MethodOverride` allows the method to be overridden if `params[:_method]` is set. This is the middleware which supports the PATCH, PUT, and DELETE HTTP method types. * `Rack::Head` converts HEAD requests to GET requests and serves them as so. diff --git a/guides/source/kindle/layout.html.erb b/guides/source/kindle/layout.html.erb index f0a286210b..fd8746776b 100644 --- a/guides/source/kindle/layout.html.erb +++ b/guides/source/kindle/layout.html.erb @@ -14,12 +14,12 @@ <% if content_for? :header_section %> <%= yield :header_section %> - <div class="pagebreak"> + <div class="pagebreak"></div> <% end %> <% if content_for? :index_section %> <%= yield :index_section %> - <div class="pagebreak"> + <div class="pagebreak"></div> <% end %> <%= yield.html_safe %> diff --git a/guides/source/kindle/toc.ncx.erb b/guides/source/kindle/toc.ncx.erb index 2c6d8e3bdf..5094fea4ca 100644 --- a/guides/source/kindle/toc.ncx.erb +++ b/guides/source/kindle/toc.ncx.erb @@ -32,12 +32,12 @@ </navPoint> <navPoint class="article" id="credits" playOrder="3"> <navLabel><text>Credits</text></navLabel> - <content src="credits.html"> + <content src="credits.html"/> </navPoint> <navPoint class="article" id="copyright" playOrder="4"> <navLabel><text>Copyright & License</text></navLabel> - <content src="copyright.html"> - </navPoint> + <content src="copyright.html"/> + </navPoint> </navPoint> <% play_order = 4 %> @@ -47,7 +47,7 @@ <text><%= section['name'] %></text> </navLabel> <content src="<%=section['documents'].first['url'] %>"/> - + <% section['documents'].each_with_index do |document, document_no| %> <navPoint class="article" id="_<%=section_no+1%>.<%=document_no+1%>" playOrder="<%=play_order +=1 %>"> <navLabel> diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index 1e2fe94010..0db90fedb3 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -121,7 +121,6 @@ use ActiveRecord::QueryCache use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash -use ActionDispatch::ParamsParser use Rack::Head use Rack::ConditionalGet use Rack::ETag @@ -284,10 +283,6 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol * Sets up the flash keys. Only available if `config.action_controller.session_store` is set to a value. -**`ActionDispatch::ParamsParser`** - -* Parses out parameters from the request into `params`. - **`Rack::Head`** * Converts HEAD requests to `GET` requests and serves them as so. diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb index 88eade5c5a..21062f3a53 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -72,7 +72,6 @@ module Rails middleware.use ::ActionDispatch::Flash end - middleware.use ::ActionDispatch::ParamsParser middleware.use ::Rack::Head middleware.use ::Rack::ConditionalGet middleware.use ::Rack::ETag, "no-cache" diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index d298e8d632..138c63266e 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -43,7 +43,6 @@ module ApplicationTests "ActionDispatch::Cookies", "ActionDispatch::Session::CookieStore", "ActionDispatch::Flash", - "ActionDispatch::ParamsParser", "Rack::Head", "Rack::ConditionalGet", "Rack::ETag" @@ -70,7 +69,6 @@ module ApplicationTests "ActionDispatch::Callbacks", "ActiveRecord::ConnectionAdapters::ConnectionManagement", "ActiveRecord::QueryCache", - "ActionDispatch::ParamsParser", "Rack::Head", "Rack::ConditionalGet", "Rack::ETag" |