From f76726c09d74c4de937054b75464857d8b8edb76 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 1 May 2011 23:23:31 -0700 Subject: Use sprockets beta gem --- actionpack/actionpack.gemspec | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack') diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 0d667a76a7..a2570587ce 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -25,6 +25,7 @@ Gem::Specification.new do |s| s.add_dependency('rack', '~> 1.2.1') s.add_dependency('rack-test', '~> 0.5.7') s.add_dependency('rack-mount', '~> 0.7.2') + s.add_dependency('sprockets', '~> 2.0.0.beta.1') s.add_dependency('tzinfo', '~> 0.3.23') s.add_dependency('erubis', '~> 2.7.0') end -- cgit v1.2.3 From c577f186aa4b7bcf12acfcc5b7fc7760d96cc663 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Tue, 3 May 2011 02:33:31 +0700 Subject: Update CHANGELOG file to mention my name On the commit for updating :format parameters, seems like I've left out the credit name after the CHANGELOG entry. This should fix it, and in case someone has a problem they could seek assistance easier. --- actionpack/CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 76dbfe7895..07a23ddb63 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -4,7 +4,9 @@ * Implicit actions named not_implemented can be rendered [Santiago Pastorino] -* Wildcard route will always matching the optional format segment by default. For example if you have this route: +* Wildcard route will always matching the optional format segment by default. [Prem Sichanugrist] + + For example if you have this route: map '*pages' => 'pages#show' -- cgit v1.2.3 From 8c9e4d520291871e5319bc0e0a890527d8aea099 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Thu, 28 Apr 2011 15:56:11 +0700 Subject: Add `ActionController::ParamsWrapper` to wrap parameters into a nested hash This will allow us to do a rootless JSON/XML request to server. --- actionpack/CHANGELOG | 4 + actionpack/lib/action_controller.rb | 1 + actionpack/lib/action_controller/base.rb | 1 + .../lib/action_controller/metal/params_wrapper.rb | 197 +++++++++++++++++++++ actionpack/test/controller/params_wrapper_test.rb | 187 +++++++++++++++++++ .../dispatch/request/json_params_parsing_test.rb | 53 ++++++ .../dispatch/request/xml_params_parsing_test.rb | 38 ++++ 7 files changed, 481 insertions(+) create mode 100644 actionpack/lib/action_controller/metal/params_wrapper.rb create mode 100644 actionpack/test/controller/params_wrapper_test.rb (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 76dbfe7895..f692b169df 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,9 @@ *Rails 3.1.0 (unreleased)* +* Add `ActionController::ParamsWrapper` to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default [Prem Sichanugrist] + + This can be customizabled by setting `ActionController::Base.wrap_parameters` in `config/initializer/wrap_parameters.rb` + * RJS has been extracted out to a gem. [fxn] * Implicit actions named not_implemented can be rendered [Santiago Pastorino] diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index aab2b9dc25..eba5e9377b 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -23,6 +23,7 @@ module ActionController autoload :ImplicitRender autoload :Instrumentation autoload :MimeResponds + autoload :ParamsWrapper autoload :RackDelegation autoload :Redirecting autoload :Renderers diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ca0dccf575..373df7fb55 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -194,6 +194,7 @@ module ActionController Caching, MimeResponds, ImplicitRender, + ParamsWrapper, Cookies, Flash, diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb new file mode 100644 index 0000000000..29ff546139 --- /dev/null +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -0,0 +1,197 @@ +require 'active_support/core_ext/class/attribute' +require 'action_dispatch/http/mime_types' + +module ActionController + # Wraps parameters hash into nested hash. This will allow client to submit + # POST request without having to specify a root element in it. + # + # By default, this functionality won't be enabled by default. You can enable + # it globally by setting +ActionController::Base.wrap_parameters+: + # + # ActionController::Base.wrap_parameters = [:json] + # + # You could also turn it on per controller by setting the format array to + # non-empty array: + # + # class UsersController < ApplicationController + # wrap_parameters :format => [:json, :xml] + # end + # + # If you enable +ParamsWrapper+ for +:json+ format. Instead of having to + # send JSON parameters like this: + # + # {"user": {"name": "Konata"}} + # + # You can now just send a parameters like this: + # + # {"name": "Konata"} + # + # And it will be wrapped into a nested hash with the key name matching + # controller's name. For example, if you're posting to +UsersController+, + # your new +params+ hash will look like this: + # + # {"name" => "Konata", "user" => {"name" => "Konata"}} + # + # You can also specify the key in which the parameters should be wrapped to, + # and also the list of attributes it should wrap by using either +:only+ or + # +:except+ options like this: + # + # class UsersController < ApplicationController + # wrap_parameters :person, :only => [:username, :password] + # end + # + # If you're going to pass the parameters to an +ActiveModel+ object (such as + # +User.new(params[:user])+), you might consider passing the model class to + # the method instead. The +ParamsWrapper+ will actually try to determine the + # list of attribute names from the model and only wrap those attributes: + # + # class UsersController < ApplicationController + # wrap_parameters Person + # end + # + # You still could pass +:only+ and +:except+ to set the list of attributes + # you want to wrap. + # + # By default, if you don't specify the key in which the parameters would be + # wrapped to, +ParamsWrapper+ will actually try to determine if there's + # a model related to it or not. This controller, for example: + # + # class Admin::UsersController < ApplicationController + # end + # + # will try to check if +Admin::User+ or +User+ model exists, and use it to + # determine the wrapper key respectively. If both of the model doesn't exists, + # it will then fallback to use +user+ as the key. + module ParamsWrapper + extend ActiveSupport::Concern + + EXCLUDE_PARAMETERS = %w(authenticity_token _method utf8) + + included do + class_attribute :_wrapper_options + self._wrapper_options = {:format => []} + end + + module ClassMethods + # Sets the name of the wrapper key, or the model which +ParamsWrapper+ + # would use to determine the attribute names from. + # + # ==== Examples + # wrap_parameters :format => :xml + # # enables the parmeter wrappes for XML format + # + # wrap_parameters :person + # # wraps parameters into +params[:person]+ hash + # + # wrap_parameters Person + # # wraps parameters by determine the wrapper key from Person class + # (+person+, in this case) and the list of attribute names + # + # wrap_parameters :only => [:username, :title] + # # wraps only +:username+ and +:title+ attributes from parameters. + # + # wrap_parameters false + # # disable parameters wrapping for this controller altogether. + # + # ==== Options + # * :format - The list of formats in which the parameters wrapper + # will be enabled. + # * :only - The list of attribute names which parmeters wrapper + # will wrap into a nested hash. + # * :only - The list of attribute names which parmeters wrapper + # will exclude from a nested hash. + def wrap_parameters(name_or_model_or_options, options = {}) + if !name_or_model_or_options.is_a? Hash + if name_or_model_or_options != false + options = options.merge(:name_or_model => name_or_model_or_options) + else + options = opions.merge(:format => []) + end + else + options = name_or_model_or_options + end + + options[:name_or_model] ||= _default_wrap_model + self._wrapper_options = self._wrapper_options.merge(options) + end + + # Sets the default wrapper key or model which will be used to determine + # wrapper key and attribute names. Will be called automatically when the + # module is inherited. + def inherited(klass) + if klass._wrapper_options[:format].present? + klass._wrapper_options = klass._wrapper_options.merge(:name_or_model => klass._default_wrap_model) + end + super + end + + # Determine the wrapper model from the controller's name. By convention, + # this could be done by trying to find the defined model that has the + # same singularize name as the controller. For example, +UsersController+ + # will try to find if the +User+ model exists. + def _default_wrap_model + model_name = self.name.sub(/Controller$/, '').singularize + + begin + model_klass = model_name.constantize + rescue NameError => e + unscoped_model_name = model_name.split("::", 2).last + break if unscoped_model_name == model_name + model_name = unscoped_model_name + end until model_klass + + model_klass + end + end + + # Performs parameters wrapping upon the request. Will be called automatically + # by the metal call stack. + def process_action(*args) + if _wrapper_enabled? + wrapped_hash = { _wrapper_key => request.request_parameters.slice(*_wrapped_keys) } + wrapped_filtered_hash = { _wrapper_key => request.filtered_parameters.slice(*_wrapped_keys) } + + # This will make the wrapped hash accessible from controller and view + request.parameters.merge! wrapped_hash + request.request_parameters.merge! wrapped_hash + + # This will make the wrapped hash displayed in the log file + request.filtered_parameters.merge! wrapped_filtered_hash + end + super + end + + private + # Returns the wrapper key which will use to stored wrapped parameters. + def _wrapper_key + @_wrapper_key ||= if _wrapper_options[:name_or_model] + _wrapper_options[:name_or_model].to_s.demodulize.underscore + else + self.class.controller_name.singularize + end + end + + # Returns the list of parameters which will be selected for wrapped. + def _wrapped_keys + @_wrapped_keys ||= if _wrapper_options[:only] + Array(_wrapper_options[:only]).collect(&:to_s) + elsif _wrapper_options[:except] + request.request_parameters.keys - Array(_wrapper_options[:except]).collect(&:to_s) - EXCLUDE_PARAMETERS + elsif _wrapper_options[:name_or_model].respond_to?(:column_names) + _wrapper_options[:name_or_model].column_names + else + request.request_parameters.keys - EXCLUDE_PARAMETERS + end + end + + # Returns the list of enabled formats. + def _wrapper_formats + Array(_wrapper_options[:format]) + end + + # Checks if we should perform parameters wrapping. + def _wrapper_enabled? + _wrapper_formats.any?{ |format| format == request.content_mime_type.try(:ref) } && request.request_parameters[_wrapper_key].nil? + end + end +end diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb new file mode 100644 index 0000000000..2e5d096fcd --- /dev/null +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -0,0 +1,187 @@ +require 'abstract_unit' + +module Admin; class User; end; end + +class ParamsWrapperTest < ActionController::TestCase + class UsersController < ActionController::Base + def test + render :json => params.except(:controller, :action) + end + end + + class User; end + class Person; end + + tests UsersController + + def test_derivered_name_from_controller + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu' } + assert_equal '{"username":"sikachu","user":{"username":"sikachu"}}', @response.body + end + end + + def test_specify_wrapper_name + with_default_wrapper_options do + UsersController.wrap_parameters :person + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu' } + assert_equal '{"username":"sikachu","person":{"username":"sikachu"}}', @response.body + end + end + + def test_specify_wrapper_model + with_default_wrapper_options do + UsersController.wrap_parameters Person + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu' } + assert_equal '{"username":"sikachu","person":{"username":"sikachu"}}', @response.body + end + end + + def test_specify_only_option + with_default_wrapper_options do + UsersController.wrap_parameters :only => :username + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer","user":{"username":"sikachu"}}', @response.body + end + end + + def test_specify_except_option + with_default_wrapper_options do + UsersController.wrap_parameters :except => :title + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer","user":{"username":"sikachu"}}', @response.body + end + end + + def test_specify_both_wrapper_name_and_only_option + with_default_wrapper_options do + UsersController.wrap_parameters :person, :only => :username + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer","person":{"username":"sikachu"}}', @response.body + end + end + + def test_not_enabled_format + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/xml' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer"}', @response.body + end + end + + def test_specify_format + with_default_wrapper_options do + UsersController.wrap_parameters :format => :xml + + @request.env['CONTENT_TYPE'] = 'application/xml' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer","user":{"username":"sikachu","title":"Developer"}}', @response.body + end + end + + def test_not_wrap_reserved_parameters + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'authenticity_token' => 'pwned', '_method' => 'put', 'utf8' => '☃', 'username' => 'sikachu' } + assert_equal '{"authenticity_token":"pwned","_method":"put","utf8":"☃","username":"sikachu","user":{"username":"sikachu"}}', @response.body + end + end + + def test_no_double_wrap_if_key_exists + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'user' => { 'username' => 'sikachu' }} + assert_equal '{"user":{"username":"sikachu"}}', @response.body + end + end + + def test_nested_params + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'person' => { 'username' => 'sikachu' }} + assert_equal '{"person":{"username":"sikachu"},"user":{"person":{"username":"sikachu"}}}', @response.body + end + end + + def test_derived_wrapped_keys_from_matching_model + with_default_wrapper_options do + User.expects(:respond_to?).with(:column_names).returns(true) + User.expects(:column_names).returns(["username"]) + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer","user":{"username":"sikachu"}}', @response.body + end + end + + def test_derived_wrapped_keys_from_specified_model + with_default_wrapper_options do + Person.expects(:respond_to?).with(:column_names).returns(true) + Person.expects(:column_names).returns(["username"]) + + UsersController.wrap_parameters Person + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer","person":{"username":"sikachu"}}', @response.body + end + end + + private + def with_default_wrapper_options(&block) + @controller.class._wrapper_options = {:format => [:json]} + @controller.class.inherited(@controller.class) + yield + end +end + +class NamespacedParamsWrapperTest < ActionController::TestCase + module Admin + class UsersController < ActionController::Base + def test + render :json => params.except(:controller, :action) + end + end + + class User; end + end + class User; end + class Person; end + + tests Admin::UsersController + + def test_derivered_name_from_controller + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu' } + assert_equal '{"username":"sikachu","user":{"username":"sikachu"}}', @response.body + end + end + + def test_namespace_lookup_when_namespaced_model_available + with_default_wrapper_options do + Admin::User.expects(:respond_to?).with(:column_names).returns(false) + + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu' } + end + end + + private + def with_default_wrapper_options(&block) + @controller.class._wrapper_options = {:format => [:json]} + @controller.class.inherited(@controller.class) + yield + end +end diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index 34db7a4c66..d854d55173 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -63,3 +63,56 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest end end end + +class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest + class UsersController < ActionController::Base + wrap_parameters :format => :json + + class << self + attr_accessor :last_request_parameters, :last_parameters + end + + def parse + self.class.last_request_parameters = request.request_parameters + self.class.last_parameters = params + head :ok + end + end + + def teardown + UsersController.last_request_parameters = nil + end + + test "parses json params for application json" do + assert_parses( + {"user" => {"username" => "sikachu"}, "username" => "sikachu"}, + "{\"username\": \"sikachu\"}", { 'CONTENT_TYPE' => 'application/json' } + ) + end + + test "parses json params for application jsonrequest" do + assert_parses( + {"user" => {"username" => "sikachu"}, "username" => "sikachu"}, + "{\"username\": \"sikachu\"}", { 'CONTENT_TYPE' => 'application/jsonrequest' } + ) + end + + private + def assert_parses(expected, actual, headers = {}) + with_test_routing(UsersController) do + post "/parse", actual, headers + assert_response :ok + assert_equal(expected, UsersController.last_request_parameters) + assert_equal(expected.merge({"action" => "parse"}), UsersController.last_parameters) + end + end + + def with_test_routing(controller) + with_routing do |set| + set.draw do + match ':action', :to => controller + end + yield + end + end +end diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb index ad9de02eb4..38453dfe48 100644 --- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb @@ -115,3 +115,41 @@ class LegacyXmlParamsParsingTest < XmlParamsParsingTest {'HTTP_X_POST_DATA_FORMAT' => 'xml'} end end + +class RootLessXmlParamsParsingTest < ActionDispatch::IntegrationTest + class TestController < ActionController::Base + wrap_parameters :person, :format => :xml + + class << self + attr_accessor :last_request_parameters + end + + def parse + self.class.last_request_parameters = request.request_parameters + head :ok + end + end + + def teardown + TestController.last_request_parameters = nil + end + + test "parses hash params" do + with_test_routing do + xml = "David" + post "/parse", xml, {'CONTENT_TYPE' => 'application/xml'} + assert_response :ok + assert_equal({"name" => "David", "person" => {"name" => "David"}}, TestController.last_request_parameters) + end + end + + private + def with_test_routing + with_routing do |set| + set.draw do + match ':action', :to => ::RootLessXmlParamsParsingTest::TestController + end + yield + end + end +end -- cgit v1.2.3 From 73c94ed97ab6639d06dade1738aa5b9f49294340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 2 May 2011 23:33:58 +0200 Subject: Add ignore_accept_header config to AD::Request. --- .../lib/action_dispatch/http/mime_negotiation.rb | 27 ++++++++++++++++++---- actionpack/test/dispatch/request_test.rb | 22 ++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 68ba1a81b5..980c658ab7 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -1,6 +1,13 @@ module ActionDispatch module Http module MimeNegotiation + extend ActiveSupport::Concern + + included do + mattr_accessor :ignore_accept_header + self.ignore_accept_header = false + end + # The MIME type of the HTTP request, such as Mime::XML. # # For backward compatibility, the post \format is extracted from the @@ -42,16 +49,14 @@ module ActionDispatch formats.first end - BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ - def formats - accept = @env['HTTP_ACCEPT'] - @env["action_dispatch.request.formats"] ||= if parameters[:format] Array(Mime[parameters[:format]]) - elsif xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) + elsif use_accept_header && valid_accept_header accepts + elsif xhr? + [Mime::JS] else [Mime::HTML] end @@ -87,6 +92,18 @@ module ActionDispatch order.include?(Mime::ALL) ? formats.first : nil end + + protected + + BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ + + def valid_accept_header + xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) + end + + def use_accept_header + !self.class.ignore_accept_header + end end end end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index f03ae7f2b3..86bbbab175 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -452,6 +452,28 @@ class RequestTest < ActiveSupport::TestCase assert request.formats.empty? end + test "ignore_accept_header" do + ActionDispatch::Request.ignore_accept_header = true + + begin + request = stub_request 'HTTP_ACCEPT' => 'application/xml' + request.expects(:parameters).at_least_once.returns({}) + assert_equal [ Mime::HTML ], request.formats + + request = stub_request 'HTTP_ACCEPT' => 'application/xml', + 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request.expects(:parameters).at_least_once.returns({}) + assert_equal [ Mime::JS ], request.formats + + request = stub_request 'HTTP_ACCEPT' => 'application/xml', + 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request.expects(:parameters).at_least_once.returns({:format => :json}) + assert_equal [ Mime::JSON ], request.formats + ensure + ActionDispatch::Request.ignore_accept_header = false + end + end + test "negotiate_mime" do request = stub_request 'HTTP_ACCEPT' => 'text/html', 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" -- cgit v1.2.3 From 83e35b9c08b97db7605542e69a8fa8d23c7df211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 2 May 2011 23:38:39 +0200 Subject: Allow ignore_accept_header through configuration option. --- actionpack/lib/action_dispatch/railtie.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 0a3bd5fe40..f51cc3711b 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -9,10 +9,12 @@ module ActionDispatch config.action_dispatch.show_exceptions = true config.action_dispatch.best_standards_support = true config.action_dispatch.tld_length = 1 + config.action_dispatch.ignore_accept_header = false config.action_dispatch.rack_cache = {:metastore => "rails:/", :entitystore => "rails:/", :verbose => true} initializer "action_dispatch.configure" do |app| ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length + ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header end end end -- cgit v1.2.3 From 11db2ae4e0f6e60c9619a808350c1550c4c78c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 2 May 2011 23:44:23 +0200 Subject: Koz asked to test something crazy. --- actionpack/test/dispatch/request_test.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 86bbbab175..fb2faf7a4e 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -460,6 +460,18 @@ class RequestTest < ActiveSupport::TestCase request.expects(:parameters).at_least_once.returns({}) assert_equal [ Mime::HTML ], request.formats + request = stub_request 'HTTP_ACCEPT' => 'koz-asked/something-crazy' + request.expects(:parameters).at_least_once.returns({}) + assert_equal [ Mime::HTML ], request.formats + + request = stub_request 'HTTP_ACCEPT' => '*/*;q=0.1' + request.expects(:parameters).at_least_once.returns({}) + assert_equal [ Mime::HTML ], request.formats + + request = stub_request 'HTTP_ACCEPT' => 'application/jxw' + request.expects(:parameters).at_least_once.returns({}) + assert_equal [ Mime::HTML ], request.formats + request = stub_request 'HTTP_ACCEPT' => 'application/xml', 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" request.expects(:parameters).at_least_once.returns({}) -- cgit v1.2.3 From c894fff60a9146754fc9f7c4ddf992634c2bedd3 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Mon, 2 May 2011 19:07:48 -0300 Subject: Fix ParamsWrapper docs errors --- actionpack/lib/action_controller/metal/params_wrapper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 29ff546139..7827ed598e 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -5,7 +5,7 @@ module ActionController # Wraps parameters hash into nested hash. This will allow client to submit # POST request without having to specify a root element in it. # - # By default, this functionality won't be enabled by default. You can enable + # By default this functionality won't be enabled. You can enable # it globally by setting +ActionController::Base.wrap_parameters+: # # ActionController::Base.wrap_parameters = [:json] @@ -78,7 +78,7 @@ module ActionController # # ==== Examples # wrap_parameters :format => :xml - # # enables the parmeter wrappes for XML format + # # enables the parmeter wrapper for XML format # # wrap_parameters :person # # wraps parameters into +params[:person]+ hash -- cgit v1.2.3 From 81cfbf4146d3c5a58054b64112b8ce196f2fc061 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 2 May 2011 15:42:38 -0700 Subject: removing auto_link and moving it to the rails_autolink gem. :bomb: --- actionpack/CHANGELOG | 6 + actionpack/lib/action_view/helpers/text_helper.rb | 125 ----------- actionpack/test/template/text_helper_test.rb | 254 ---------------------- 3 files changed, 6 insertions(+), 379 deletions(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 184b2af018..448ee878b1 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,11 @@ *Rails 3.1.0 (unreleased)* +* auto_link has been removed with no replacement. If you still use auto_link + please install the rails_autolink gem: + http://github.com/tenderlove/rails_autolink + + [tenderlove] + * Add `ActionController::ParamsWrapper` to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default [Prem Sichanugrist] This can be customizabled by setting `ActionController::Base.wrap_parameters` in `config/initializer/wrap_parameters.rb` diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 06e2b027da..ca09c77b5c 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -265,60 +265,6 @@ module ActionView text.html_safe.safe_concat("

") end - # Turns all URLs and e-mail addresses into clickable links. The :link option - # will limit what should be linked. You can add HTML attributes to the links using - # :html. Possible values for :link are :all (default), - # :email_addresses, and :urls. If a block is given, each URL and - # e-mail address is yielded and the result is used as the link text. - # - # ==== Examples - # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com") - # # => "Go to http://www.rubyonrails.org and - # # say hello to david@loudthinking.com" - # - # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls) - # # => "Visit http://www.loudthinking.com/ - # # or e-mail david@loudthinking.com" - # - # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses) - # # => "Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com" - # - # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com." - # auto_link(post_body, :html => { :target => '_blank' }) do |text| - # truncate(text, :length => 15) - # end - # # => "Welcome to my new blog at http://www.m.... - # Please e-mail me at me@email.com." - # - # - # You can still use auto_link with the old API that accepts the - # +link+ as its optional second parameter and the +html_options+ hash - # as its optional third parameter: - # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com." - # auto_link(post_body, :urls) - # # => "Welcome to my new blog at http://www.myblog.com. - # Please e-mail me at me@email.com." - # - # auto_link(post_body, :all, :target => "_blank") - # # => "Welcome to my new blog at http://www.myblog.com. - # Please e-mail me at me@email.com." - def auto_link(text, *args, &block)#link = :all, html = {}, &block) - return '' if text.blank? - - options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter - unless args.empty? - options[:link] = args[0] || :all - options[:html] = args[1] || {} - end - options.reverse_merge!(:link => :all, :html => {}) - - case options[:link].to_sym - when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block) - when :email_addresses then auto_link_email_addresses(text, options[:html], &block) - when :urls then auto_link_urls(text, options[:html], options, &block) - end - end - # Creates a Cycle object whose _to_s_ method cycles through elements of an # array every time it is called. This can be used for example, to alternate # classes for table rows. You can use named cycles to allow nesting in loops. @@ -464,77 +410,6 @@ module ActionView @_cycles = Hash.new unless defined?(@_cycles) @_cycles[name] = cycle_object end - - AUTO_LINK_RE = %r{ - (?: ([0-9A-Za-z+.:-]+:)// | www\. ) - [^\s<]+ - }x - - # regexps for determining context, used high-volume - AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, //i, /<\/a>/i] - - AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/ - - BRACKETS = { ']' => '[', ')' => '(', '}' => '{' } - - # Turns all urls into clickable links. If a block is given, each url - # is yielded and the result is used as the link text. - def auto_link_urls(text, html_options = {}, options = {}) - link_attributes = html_options.stringify_keys - text.gsub(AUTO_LINK_RE) do - scheme, href = $1, $& - punctuation = [] - - if auto_linked?($`, $') - # do not change string; URL is already linked - href - else - # don't include trailing punctuation character as part of the URL - while href.sub!(/[^\w\/-]$/, '') - punctuation.push $& - if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size - href << punctuation.pop - break - end - end - - link_text = block_given?? yield(href) : href - href = 'http://' + href unless scheme - - unless options[:sanitize] == false - link_text = sanitize(link_text) - href = sanitize(href) - end - content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('') - end - end - end - - # Turns all email addresses into clickable links. If a block is given, - # each email is yielded and the result is used as the link text. - def auto_link_email_addresses(text, html_options = {}, options = {}) - text.gsub(AUTO_EMAIL_RE) do - text = $& - - if auto_linked?($`, $') - text.html_safe - else - display_text = (block_given?) ? yield(text) : text - - unless options[:sanitize] == false - text = sanitize(text) - display_text = sanitize(display_text) unless text == display_text - end - mail_to text, display_text, html_options - end - end - end - - # Detects already linked context or position in the middle of a tag - def auto_linked?(left, right) - (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or - (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3]) - end end end end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index a4fcff5167..740f577a6e 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -278,260 +278,6 @@ class TextHelperTest < ActionView::TestCase assert_equal("12 berries", pluralize(12, "berry")) end - def test_auto_link_parsing - urls = %w( - http://www.rubyonrails.com - http://www.rubyonrails.com:80 - http://www.rubyonrails.com/~minam - https://www.rubyonrails.com/~minam - http://www.rubyonrails.com/~minam/url%20with%20spaces - http://www.rubyonrails.com/foo.cgi?something=here - http://www.rubyonrails.com/foo.cgi?something=here&and=here - http://www.rubyonrails.com/contact;new - http://www.rubyonrails.com/contact;new%20with%20spaces - http://www.rubyonrails.com/contact;new?with=query&string=params - http://www.rubyonrails.com/~minam/contact;new?with=query&string=params - http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007 - http://www.mail-archive.com/rails@lists.rubyonrails.org/ - http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1 - http://en.wikipedia.org/wiki/Texas_hold'em - https://www.google.com/doku.php?id=gps:resource:scs:start - http://connect.oraclecorp.com/search?search[q]=green+france&search[type]=Group - http://of.openfoundry.org/projects/492/download#4th.Release.3 - http://maps.google.co.uk/maps?f=q&q=the+london+eye&ie=UTF8&ll=51.503373,-0.11939&spn=0.007052,0.012767&z=16&iwloc=A - ) - - urls.each do |url| - assert_equal generate_result(url), auto_link(url) - end - end - - def generate_result(link_text, href = nil, escape = false) - href ||= link_text - if escape - %{#{CGI::escapeHTML link_text}} - else - %{#{link_text}} - end - end - - def test_auto_link_should_not_be_html_safe - email_raw = 'santiago@wyeworks.com' - link_raw = 'http://www.rubyonrails.org' - - assert !auto_link(nil).html_safe?, 'should not be html safe' - assert !auto_link('').html_safe?, 'should not be html safe' - assert !auto_link("#{link_raw} #{link_raw} #{link_raw}").html_safe?, 'should not be html safe' - assert !auto_link("hello #{email_raw}").html_safe?, 'should not be html safe' - end - - def test_auto_link_email_address - email_raw = 'aaron@tenderlovemaking.com' - email_result = %{#{email_raw}} - assert !auto_link_email_addresses(email_result).html_safe?, 'should not be html safe' - end - - def test_auto_link - email_raw = 'david@loudthinking.com' - email_result = %{#{email_raw}} - link_raw = 'http://www.rubyonrails.com' - link_result = generate_result(link_raw) - link_result_with_options = %{#{link_raw}} - - assert_equal '', auto_link(nil) - assert_equal '', auto_link('') - assert_equal "#{link_result} #{link_result} #{link_result}", auto_link("#{link_raw} #{link_raw} #{link_raw}") - - assert_equal %(hello #{email_result}), auto_link("hello #{email_raw}", :email_addresses) - assert_equal %(Go to #{link_result}), auto_link("Go to #{link_raw}", :urls) - assert_equal %(Go to #{link_raw}), auto_link("Go to #{link_raw}", :email_addresses) - assert_equal %(Go to #{link_result} and say hello to #{email_result}), auto_link("Go to #{link_raw} and say hello to #{email_raw}") - assert_equal %(

Link #{link_result}

), auto_link("

Link #{link_raw}

") - assert_equal %(

#{link_result} Link

), auto_link("

#{link_raw} Link

") - assert_equal %(

Link #{link_result_with_options}

), auto_link("

Link #{link_raw}

", :all, {:target => "_blank"}) - assert_equal %(Go to #{link_result}.), auto_link(%(Go to #{link_raw}.)) - assert_equal %(

Go to #{link_result}, then say hello to #{email_result}.

), auto_link(%(

Go to #{link_raw}, then say hello to #{email_raw}.

)) - assert_equal %(#{link_result} #{link_result}), auto_link(%(#{link_result} #{link_raw})) - - email2_raw = '+david@loudthinking.com' - email2_result = %{#{email2_raw}} - assert_equal email2_result, auto_link(email2_raw) - - email3_raw = '+david@loudthinking.com' - email3_result = %{#{email3_raw}} - assert_equal email3_result, auto_link(email3_raw, :all, :encode => :hex) - assert_equal email3_result, auto_link(email3_raw, :email_addresses, :encode => :hex) - - link2_raw = 'www.rubyonrails.com' - link2_result = generate_result(link2_raw, "http://#{link2_raw}") - assert_equal %(Go to #{link2_result}), auto_link("Go to #{link2_raw}", :urls) - assert_equal %(Go to #{link2_raw}), auto_link("Go to #{link2_raw}", :email_addresses) - assert_equal %(

Link #{link2_result}

), auto_link("

Link #{link2_raw}

") - assert_equal %(

#{link2_result} Link

), auto_link("

#{link2_raw} Link

") - assert_equal %(Go to #{link2_result}.), auto_link(%(Go to #{link2_raw}.)) - assert_equal %(

Say hello to #{email_result}, then go to #{link2_result}.

), auto_link(%(

Say hello to #{email_raw}, then go to #{link2_raw}.

)) - - link3_raw = 'http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281' - link3_result = generate_result(link3_raw) - assert_equal %(Go to #{link3_result}), auto_link("Go to #{link3_raw}", :urls) - assert_equal %(Go to #{link3_raw}), auto_link("Go to #{link3_raw}", :email_addresses) - assert_equal %(

Link #{link3_result}

), auto_link("

Link #{link3_raw}

") - assert_equal %(

#{link3_result} Link

), auto_link("

#{link3_raw} Link

") - assert_equal %(Go to #{link3_result}.), auto_link(%(Go to #{link3_raw}.)) - assert_equal %(

Go to #{link3_result}. Seriously, #{link3_result}? I think I'll say hello to #{email_result}. Instead.

), - auto_link(%(

Go to #{link3_raw}. Seriously, #{link3_raw}? I think I'll say hello to #{email_raw}. Instead.

)) - - link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123' - link4_result = generate_result(link4_raw) - assert_equal %(

Link #{link4_result}

), auto_link("

Link #{link4_raw}

") - assert_equal %(

#{link4_result} Link

), auto_link("

#{link4_raw} Link

") - - link5_raw = 'http://foo.example.com:3000/controller/action' - link5_result = generate_result(link5_raw) - assert_equal %(

#{link5_result} Link

), auto_link("

#{link5_raw} Link

") - - link6_raw = 'http://foo.example.com:3000/controller/action+pack' - link6_result = generate_result(link6_raw) - assert_equal %(

#{link6_result} Link

), auto_link("

#{link6_raw} Link

") - - link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123' - link7_result = generate_result(link7_raw) - assert_equal %(

#{link7_result} Link

), auto_link("

#{link7_raw} Link

") - - link8_raw = 'http://foo.example.com:3000/controller/action.html' - link8_result = generate_result(link8_raw) - assert_equal %(Go to #{link8_result}), auto_link("Go to #{link8_raw}", :urls) - assert_equal %(Go to #{link8_raw}), auto_link("Go to #{link8_raw}", :email_addresses) - assert_equal %(

Link #{link8_result}

), auto_link("

Link #{link8_raw}

") - assert_equal %(

#{link8_result} Link

), auto_link("

#{link8_raw} Link

") - assert_equal %(Go to #{link8_result}.), auto_link(%(Go to #{link8_raw}.)) - assert_equal %(

Go to #{link8_result}. Seriously, #{link8_result}? I think I'll say hello to #{email_result}. Instead.

), - auto_link(%(

Go to #{link8_raw}. Seriously, #{link8_raw}? I think I'll say hello to #{email_raw}. Instead.

)) - - link9_raw = 'http://business.timesonline.co.uk/article/0,,9065-2473189,00.html' - link9_result = generate_result(link9_raw) - assert_equal %(Go to #{link9_result}), auto_link("Go to #{link9_raw}", :urls) - assert_equal %(Go to #{link9_raw}), auto_link("Go to #{link9_raw}", :email_addresses) - assert_equal %(

Link #{link9_result}

), auto_link("

Link #{link9_raw}

") - assert_equal %(

#{link9_result} Link

), auto_link("

#{link9_raw} Link

") - assert_equal %(Go to #{link9_result}.), auto_link(%(Go to #{link9_raw}.)) - assert_equal %(

Go to #{link9_result}. Seriously, #{link9_result}? I think I'll say hello to #{email_result}. Instead.

), - auto_link(%(

Go to #{link9_raw}. Seriously, #{link9_raw}? I think I'll say hello to #{email_raw}. Instead.

)) - - link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/' - link10_result = generate_result(link10_raw) - assert_equal %(

#{link10_result} Link

), auto_link("

#{link10_raw} Link

") - - link11_raw = 'http://asakusa.rubyist.net/' - link11_result = generate_result(link11_raw) - with_kcode 'u' do - assert_equal %(浅草.rbの公式サイトはこちら#{link11_result}), auto_link("浅草.rbの公式サイトはこちら#{link11_raw}") - end - end - - def test_auto_link_should_sanitize_input_when_sanitize_option_is_not_false - link_raw = %{http://www.rubyonrails.com?id=1&num=2} - assert_equal %{http://www.rubyonrails.com?id=1&num=2}, auto_link(link_raw) - end - - def test_auto_link_should_not_sanitize_input_when_sanitize_option_is_false - link_raw = %{http://www.rubyonrails.com?id=1&num=2} - assert_equal %{http://www.rubyonrails.com?id=1&num=2}, auto_link(link_raw, :sanitize => false) - end - - def test_auto_link_other_protocols - ftp_raw = 'ftp://example.com/file.txt' - assert_equal %(Download #{generate_result(ftp_raw)}), auto_link("Download #{ftp_raw}") - - file_scheme = 'file:///home/username/RomeoAndJuliet.pdf' - z39_scheme = 'z39.50r://host:696/db' - chrome_scheme = 'chrome://package/section/path' - view_source = 'view-source:http://en.wikipedia.org/wiki/URI_scheme' - assert_equal generate_result(file_scheme), auto_link(file_scheme) - assert_equal generate_result(z39_scheme), auto_link(z39_scheme) - assert_equal generate_result(chrome_scheme), auto_link(chrome_scheme) - assert_equal generate_result(view_source), auto_link(view_source) - end - - def test_auto_link_already_linked - linked1 = generate_result('Ruby On Rails', 'http://www.rubyonrails.com') - linked2 = %('www.example.com') - linked3 = %('www.example.com') - linked4 = %('www.example.com') - linked5 = %('close www.example.com') - assert_equal linked1, auto_link(linked1) - assert_equal linked2, auto_link(linked2) - assert_equal linked3, auto_link(linked3) - assert_equal linked4, auto_link(linked4) - assert_equal linked5, auto_link(linked5) - - linked_email = %Q(Mail me) - assert_equal linked_email, auto_link(linked_email) - end - - def test_auto_link_within_tags - link_raw = 'http://www.rubyonrails.org/images/rails.png' - link_result = %Q() - assert_equal link_result, auto_link(link_result) - end - - def test_auto_link_with_brackets - link1_raw = 'http://en.wikipedia.org/wiki/Sprite_(computer_graphics)' - link1_result = generate_result(link1_raw) - assert_equal link1_result, auto_link(link1_raw) - assert_equal "(link: #{link1_result})", auto_link("(link: #{link1_raw})") - - link2_raw = 'http://en.wikipedia.org/wiki/Sprite_[computer_graphics]' - link2_result = generate_result(link2_raw) - assert_equal link2_result, auto_link(link2_raw) - assert_equal "[link: #{link2_result}]", auto_link("[link: #{link2_raw}]") - - link3_raw = 'http://en.wikipedia.org/wiki/Sprite_{computer_graphics}' - link3_result = generate_result(link3_raw) - assert_equal link3_result, auto_link(link3_raw) - assert_equal "{link: #{link3_result}}", auto_link("{link: #{link3_raw}}") - end - - def test_auto_link_at_eol - url1 = "http://api.rubyonrails.com/Foo.html" - url2 = "http://www.ruby-doc.org/core/Bar.html" - - assert_equal %(

#{url1}
#{url2}

), auto_link("

#{url1}
#{url2}

") - end - - def test_auto_link_with_block - url = "http://api.rubyonrails.com/Foo.html" - email = "fantabulous@shiznadel.ic" - - assert_equal %(

#{url[0...7]}...
#{email[0...7]}...

), auto_link("

#{url}
#{email}

") { |_url| truncate(_url, :length => 10) } - end - - def test_auto_link_with_block_with_html - pic = "http://example.com/pic.png" - url = "http://example.com/album?a&b=c" - - assert_equal %(My pic: -- full album here #{generate_result(url)}), auto_link("My pic: #{pic} -- full album here #{url}") { |link| - if link =~ /\.(jpg|gif|png|bmp|tif)$/i - raw %() - else - link - end - } - end - - def test_auto_link_with_options_hash - assert_dom_equal 'Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.', - auto_link("Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.", - :link => :all, :html => { :class => "menu", :target => "_blank" }) - end - - def test_auto_link_with_multiple_trailing_punctuations - url = "http://youtube.com" - url_result = generate_result(url) - assert_equal url_result, auto_link(url) - assert_equal "(link: #{url_result}).", auto_link("(link: #{url}).") - end - def test_cycle_class value = Cycle.new("one", 2, "3") assert_equal("one", value.to_s) -- cgit v1.2.3 From 3cca86641e91400e3317ce2d03b483edf1db3ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 2 May 2011 23:53:53 +0200 Subject: Update CHANGELOG. --- actionpack/CHANGELOG | 20 ++++++++++++++++---- actionpack/lib/action_controller/metal/streaming.rb | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 448ee878b1..ba01c4749f 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -6,15 +6,27 @@ [tenderlove] -* Add `ActionController::ParamsWrapper` to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default [Prem Sichanugrist] +* Added streaming support, you can enable it with: [José Valim] - This can be customizabled by setting `ActionController::Base.wrap_parameters` in `config/initializer/wrap_parameters.rb` + class PostsController < ActionController::Base + stream :only => :index + end + + Please read the docs at `ActionController::Streaming` for more information. + +* Added `ActionDispatch::Request.ignore_accept_header` to ignore accept headers and only consider the format given as parameter [José Valim] + +* Created `ActionView::Renderer` and specified an API for `ActionView::Context`, check those objects for more information [José Valim] + +* Added `ActionController::ParamsWrapper` to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default [Prem Sichanugrist] + + This can be customized by setting `ActionController::Base.wrap_parameters` in `config/initializer/wrap_parameters.rb` * RJS has been extracted out to a gem. [fxn] -* Implicit actions named not_implemented can be rendered [Santiago Pastorino] +* Implicit actions named not_implemented can be rendered. [Santiago Pastorino] -* Wildcard route will always matching the optional format segment by default. [Prem Sichanugrist] +* Wildcard route will always match the optional format segment by default. [Prem Sichanugrist] For example if you have this route: diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 1d27c3aa51..3892a12407 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -160,7 +160,7 @@ module ActionController #:nodoc: # needs to inject contents in the HTML body. # # Also +Rack::Cache+ won't work with streaming as it does not support - # streaming bodies yet. So, whenever streaming, Cache-Control is automatically + # streaming bodies yet. Whenever streaming Cache-Control is automatically # set to "no-cache". # # == Errors -- cgit v1.2.3 From 4bddc06e83acecce662b4282159c5eb0096c4783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 3 May 2011 00:37:40 +0200 Subject: Move most processing to load time for performance and improve test suite. --- .../lib/action_controller/metal/params_wrapper.rb | 74 ++++++++++++++-------- actionpack/test/controller/params_wrapper_test.rb | 39 ++++++++---- 2 files changed, 76 insertions(+), 37 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 7827ed598e..3262e24f67 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -1,4 +1,6 @@ require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/array/wrap' require 'action_dispatch/http/mime_types' module ActionController @@ -96,23 +98,25 @@ module ActionController # ==== Options # * :format - The list of formats in which the parameters wrapper # will be enabled. - # * :only - The list of attribute names which parmeters wrapper + # * :only - The list of attribute names which parameters wrapper # will wrap into a nested hash. - # * :only - The list of attribute names which parmeters wrapper + # * :except - The list of attribute names which parameters wrapper # will exclude from a nested hash. def wrap_parameters(name_or_model_or_options, options = {}) - if !name_or_model_or_options.is_a? Hash - if name_or_model_or_options != false - options = options.merge(:name_or_model => name_or_model_or_options) - else - options = opions.merge(:format => []) - end - else + model = nil + + case name_or_model_or_options + when Hash options = name_or_model_or_options + when false + options = options.merge(:format => []) + when Symbol, String + options = options.merge(:name => name_or_model_or_options) + else + model = name_or_model_or_options end - options[:name_or_model] ||= _default_wrap_model - self._wrapper_options = self._wrapper_options.merge(options) + _set_wrapper_defaults(_wrapper_options.slice(:format).merge(options), model) end # Sets the default wrapper key or model which will be used to determine @@ -120,11 +124,13 @@ module ActionController # module is inherited. def inherited(klass) if klass._wrapper_options[:format].present? - klass._wrapper_options = klass._wrapper_options.merge(:name_or_model => klass._default_wrap_model) + klass._set_wrapper_defaults(klass._wrapper_options) end super end + protected + # Determine the wrapper model from the controller's name. By convention, # this could be done by trying to find the defined model that has the # same singularize name as the controller. For example, +UsersController+ @@ -142,6 +148,29 @@ module ActionController model_klass end + + def _set_wrapper_defaults(options, model=nil) + options = options.dup + + unless options[:only] || options[:except] + model ||= _default_wrap_model + if model.respond_to?(:column_names) + options[:only] = model.column_names + end + end + + unless options[:name] + model ||= _default_wrap_model + options[:name] = model ? model.to_s.demodulize.underscore : + controller_name.singularize + end + + options[:only] = Array.wrap(options[:only]).collect(&:to_s) if options[:only] + options[:except] = Array.wrap(options[:except]).collect(&:to_s) if options[:except] + options[:format] = Array.wrap(options[:format]) + + self._wrapper_options = options + end end # Performs parameters wrapping upon the request. Will be called automatically @@ -164,21 +193,15 @@ module ActionController private # Returns the wrapper key which will use to stored wrapped parameters. def _wrapper_key - @_wrapper_key ||= if _wrapper_options[:name_or_model] - _wrapper_options[:name_or_model].to_s.demodulize.underscore - else - self.class.controller_name.singularize - end + _wrapper_options[:name] end # Returns the list of parameters which will be selected for wrapped. def _wrapped_keys - @_wrapped_keys ||= if _wrapper_options[:only] - Array(_wrapper_options[:only]).collect(&:to_s) - elsif _wrapper_options[:except] - request.request_parameters.keys - Array(_wrapper_options[:except]).collect(&:to_s) - EXCLUDE_PARAMETERS - elsif _wrapper_options[:name_or_model].respond_to?(:column_names) - _wrapper_options[:name_or_model].column_names + @_wrapped_keys ||= if only = _wrapper_options[:only] + only + elsif except = _wrapper_options[:except] + request.request_parameters.keys - except - EXCLUDE_PARAMETERS else request.request_parameters.keys - EXCLUDE_PARAMETERS end @@ -186,12 +209,13 @@ module ActionController # Returns the list of enabled formats. def _wrapper_formats - Array(_wrapper_options[:format]) + _wrapper_options[:format] end # Checks if we should perform parameters wrapping. def _wrapper_enabled? - _wrapper_formats.any?{ |format| format == request.content_mime_type.try(:ref) } && request.request_parameters[_wrapper_key].nil? + ref = request.content_mime_type.try(:ref) + _wrapper_formats.any? { |format| format == ref } && !request.request_parameters[_wrapper_key] end end end diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index 2e5d096fcd..314b27cf47 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -80,6 +80,15 @@ class ParamsWrapperTest < ActionController::TestCase end end + def test_wrap_parameters_false + with_default_wrapper_options do + UsersController.wrap_parameters false + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer"}', @response.body + end + end + def test_specify_format with_default_wrapper_options do UsersController.wrap_parameters :format => :xml @@ -115,10 +124,10 @@ class ParamsWrapperTest < ActionController::TestCase end def test_derived_wrapped_keys_from_matching_model - with_default_wrapper_options do - User.expects(:respond_to?).with(:column_names).returns(true) - User.expects(:column_names).returns(["username"]) + User.expects(:respond_to?).with(:column_names).returns(true) + User.expects(:column_names).returns(["username"]) + with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' post :test, { 'username' => 'sikachu', 'title' => 'Developer' } assert_equal '{"username":"sikachu","title":"Developer","user":{"username":"sikachu"}}', @response.body @@ -153,11 +162,13 @@ class NamespacedParamsWrapperTest < ActionController::TestCase render :json => params.except(:controller, :action) end end + end - class User; end + class Sample + def self.column_names + ["username"] + end end - class User; end - class Person; end tests Admin::UsersController @@ -169,12 +180,16 @@ class NamespacedParamsWrapperTest < ActionController::TestCase end end - def test_namespace_lookup_when_namespaced_model_available - with_default_wrapper_options do - Admin::User.expects(:respond_to?).with(:column_names).returns(false) - - @request.env['CONTENT_TYPE'] = 'application/json' - post :test, { 'username' => 'sikachu' } + def test_namespace_lookup_from_model + Admin.const_set(:User, Class.new(Sample)) + begin + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :test, { 'username' => 'sikachu', 'title' => 'Developer' } + assert_equal '{"username":"sikachu","title":"Developer","user":{"username":"sikachu"}}', @response.body + end + ensure + Admin.send :remove_const, :User end end -- cgit v1.2.3 From 1afb56f4818381098c6ed0babc4a5899e324e2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 3 May 2011 00:47:11 +0200 Subject: Instrumentation should have callbacks. --- actionpack/lib/action_controller/base.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 373df7fb55..ccf1632a14 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -207,14 +207,14 @@ module ActionController HttpAuthentication::Digest::ControllerMethods, HttpAuthentication::Token::ControllerMethods, - # Add instrumentations hooks at the bottom, to ensure they instrument - # all the methods properly. - Instrumentation, - # Before callbacks should also be executed the earliest as possible, so # also include them at the bottom. AbstractController::Callbacks, + # Add instrumentations hooks at the bottom, to ensure they instrument + # all the methods properly. + Instrumentation, + # The same with rescue, append it at the end to wrap as much as possible. Rescue ] -- cgit v1.2.3 From a55f2de0c5baae589b1730df1e4068f0cd1474ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 3 May 2011 01:03:21 +0200 Subject: Improve performance for filtered parameters and add tests. --- actionpack/lib/action_controller/base.rb | 5 ++++- actionpack/lib/action_controller/metal/instrumentation.rb | 2 +- actionpack/lib/action_controller/metal/params_wrapper.rb | 5 ++--- actionpack/lib/action_dispatch/http/filter_parameters.rb | 5 +++++ actionpack/test/controller/log_subscriber_test.rb | 11 +++++++++++ 5 files changed, 23 insertions(+), 5 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ccf1632a14..c03c77cb4a 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -194,7 +194,6 @@ module ActionController Caching, MimeResponds, ImplicitRender, - ParamsWrapper, Cookies, Flash, @@ -215,6 +214,10 @@ module ActionController # all the methods properly. Instrumentation, + # Params wrapper should come before instrumentation so they are + # properly showed in logs + ParamsWrapper, + # The same with rescue, append it at the end to wrap as much as possible. Rescue ] diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb index dc3ea939e6..4e54c2ad88 100644 --- a/actionpack/lib/action_controller/metal/instrumentation.rb +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -14,7 +14,7 @@ module ActionController attr_internal :view_runtime - def process_action(action, *args) + def process_action(*args) raw_payload = { :controller => self.class.name, :action => self.action_name, diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 3262e24f67..d128f6d03c 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -178,14 +178,13 @@ module ActionController def process_action(*args) if _wrapper_enabled? wrapped_hash = { _wrapper_key => request.request_parameters.slice(*_wrapped_keys) } - wrapped_filtered_hash = { _wrapper_key => request.filtered_parameters.slice(*_wrapped_keys) } # This will make the wrapped hash accessible from controller and view request.parameters.merge! wrapped_hash request.request_parameters.merge! wrapped_hash # This will make the wrapped hash displayed in the log file - request.filtered_parameters.merge! wrapped_filtered_hash + request.clear_filtered_parameters end super end @@ -215,7 +214,7 @@ module ActionController # Checks if we should perform parameters wrapping. def _wrapper_enabled? ref = request.content_mime_type.try(:ref) - _wrapper_formats.any? { |format| format == ref } && !request.request_parameters[_wrapper_key] + _wrapper_formats.include?(ref) && !request.request_parameters[_wrapper_key] end end end diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb index 8dd1af7f3d..9c5b6a6b88 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -33,6 +33,11 @@ module ActionDispatch @filtered_parameters ||= parameter_filter.filter(parameters) end + # Clear any filtered parameters forcing them to be filtered again. + def clear_filtered_parameters + @filtered_parameters = nil + end + # Return a hash of request.env with all sensitive data replaced. def filtered_env @filtered_env ||= env_filter.filter(@env) diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb index ddfa3df552..5d7a51e902 100644 --- a/actionpack/test/controller/log_subscriber_test.rb +++ b/actionpack/test/controller/log_subscriber_test.rb @@ -4,6 +4,8 @@ require "action_controller/log_subscriber" module Another class LogSubscribersController < ActionController::Base + wrap_parameters :person, :only => :name, :format => :json + def show render :nothing => true end @@ -95,6 +97,15 @@ class ACLogSubscriberTest < ActionController::TestCase assert_equal 'Parameters: {"id"=>"10"}', logs[1] end + def test_process_action_with_wrapped_parameters + @request.env['CONTENT_TYPE'] = 'application/json' + post :show, :id => '10', :name => 'jose' + wait + + assert_equal 3, logs.size + assert_match '"person"=>{"name"=>"jose"}', logs[1] + end + def test_process_action_with_view_runtime get :show wait -- cgit v1.2.3 From 35d0d82ae3edf8fe959624999c858a63b2b4ed52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 3 May 2011 01:36:58 +0200 Subject: More performance optimizations. --- .../lib/action_controller/metal/params_wrapper.rb | 30 ++++++++++++---------- .../lib/action_dispatch/http/filter_parameters.rb | 5 ---- 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index d128f6d03c..21bbe17dc3 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/hash/except' require 'active_support/core_ext/array/wrap' require 'action_dispatch/http/mime_types' @@ -177,40 +178,43 @@ module ActionController # by the metal call stack. def process_action(*args) if _wrapper_enabled? - wrapped_hash = { _wrapper_key => request.request_parameters.slice(*_wrapped_keys) } + wrapped_hash = _wrap_parameters request.request_parameters + wrapped_filtered_hash = _wrap_parameters request.filtered_parameters # This will make the wrapped hash accessible from controller and view request.parameters.merge! wrapped_hash request.request_parameters.merge! wrapped_hash # This will make the wrapped hash displayed in the log file - request.clear_filtered_parameters + request.filtered_parameters.merge! wrapped_filtered_hash end super end private + # Returns the wrapper key which will use to stored wrapped parameters. def _wrapper_key _wrapper_options[:name] end - # Returns the list of parameters which will be selected for wrapped. - def _wrapped_keys - @_wrapped_keys ||= if only = _wrapper_options[:only] - only - elsif except = _wrapper_options[:except] - request.request_parameters.keys - except - EXCLUDE_PARAMETERS - else - request.request_parameters.keys - EXCLUDE_PARAMETERS - end - end - # Returns the list of enabled formats. def _wrapper_formats _wrapper_options[:format] end + # Returns the list of parameters which will be selected for wrapped. + def _wrap_parameters(parameters) + value = if only = _wrapper_options[:only] + parameters.slice(*only) + else + except = _wrapper_options[:except] || [] + parameters.except(*(except + EXCLUDE_PARAMETERS)) + end + + { _wrapper_key => value } + end + # Checks if we should perform parameters wrapping. def _wrapper_enabled? ref = request.content_mime_type.try(:ref) diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb index 9c5b6a6b88..8dd1af7f3d 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -33,11 +33,6 @@ module ActionDispatch @filtered_parameters ||= parameter_filter.filter(parameters) end - # Clear any filtered parameters forcing them to be filtered again. - def clear_filtered_parameters - @filtered_parameters = nil - end - # Return a hash of request.env with all sensitive data replaced. def filtered_env @filtered_env ||= env_filter.filter(@env) -- cgit v1.2.3