diff options
Diffstat (limited to 'actionpack')
26 files changed, 323 insertions, 130 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index dc52262503..314aa7181c 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,19 @@ ## Rails 3.2.0 (unreleased) ## +* You can provide a namespace for your form to ensure uniqueness of id attributes on form elements. + The namespace attribute will be prefixed with underscore on the generate HTML id. *Vasiliy Ermolovich* + + Example: + + <%= form_for(@offer, :namespace => 'namespace') do |f| %> + <%= f.label :version, 'Version' %>: + <%= f.text_field :version %> + <% end %> + +* Refactor ActionDispatch::ShowExceptions. Controller is responsible for choice to show exceptions. *Sergey Nartimov* + + It's possible to override +show_detailed_exceptions?+ in controllers to specify which requests should provide debugging information on errors. + * Responders now return 204 No Content for API requests without a response body (as in the new scaffold) *José Valim* * Added ActionDispatch::RequestId middleware that'll make a unique X-Request-Id header available to the response and enables the ActionDispatch::Request#uuid method. This makes it easy to trace requests from end-to-end in the stack and to identify individual requests in mixed logs like Syslog *DHH* diff --git a/actionpack/lib/abstract_controller/railties/routes_helpers.rb b/actionpack/lib/abstract_controller/railties/routes_helpers.rb index dec1e9d6d9..6684f46f64 100644 --- a/actionpack/lib/abstract_controller/railties/routes_helpers.rb +++ b/actionpack/lib/abstract_controller/railties/routes_helpers.rb @@ -5,8 +5,8 @@ module AbstractController Module.new do define_method(:inherited) do |klass| super(klass) - if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) } - klass.send(:include, namespace._railtie.routes.url_helpers) + if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) } + klass.send(:include, namespace.railtie_routes_url_helpers) else klass.send(:include, routes.url_helpers) end diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 0ad9dbeda9..6e9ce450ac 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/object/blank' +require 'set' module ActionController # See <tt>Renderers.add</tt> @@ -12,16 +13,13 @@ module ActionController included do class_attribute :_renderers - self._renderers = {}.freeze + self._renderers = Set.new.freeze end module ClassMethods def use_renderers(*args) - new = _renderers.dup - args.each do |key| - new[key] = RENDERERS[key] - end - self._renderers = new.freeze + renderers = _renderers + args + self._renderers = renderers.freeze end alias use_renderer use_renderers end @@ -31,10 +29,10 @@ module ActionController end def _handle_render_options(options) - _renderers.each do |name, value| - if options.key?(name.to_sym) + _renderers.each do |name| + if options.key?(name) _process_options(options) - return send("_render_option_#{name}", options.delete(name.to_sym), options) + return send("_render_option_#{name}", options.delete(name), options) end end nil @@ -42,7 +40,7 @@ module ActionController # Hash of available renderers, mapping a renderer name to its proc. # Default keys are :json, :js, :xml. - RENDERERS = {} + RENDERERS = Set.new # Adds a new renderer to call within controller actions. # A renderer is invoked by passing its name as an option to @@ -79,7 +77,7 @@ module ActionController # <tt>ActionController::MimeResponds#respond_with</tt> def self.add(key, &block) define_method("_render_option_#{key}", &block) - RENDERERS[key] = block + RENDERERS << key.to_sym end module All diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb index eb037aa1b0..736ff5b31c 100644 --- a/actionpack/lib/action_controller/metal/rescue.rb +++ b/actionpack/lib/action_controller/metal/rescue.rb @@ -3,6 +3,11 @@ module ActionController #:nodoc: extend ActiveSupport::Concern include ActiveSupport::Rescuable + included do + config_accessor :consider_all_requests_local + self.consider_all_requests_local = false if consider_all_requests_local.nil? + end + def rescue_with_handler(exception) if (exception.respond_to?(:original_exception) && (orig_exception = exception.original_exception) && @@ -12,10 +17,15 @@ module ActionController #:nodoc: super(exception) end + def show_detailed_exceptions? + consider_all_requests_local || request.local? + end + private def process_action(*args) super rescue Exception => exception + request.env['action_dispatch.show_detailed_exceptions'] = show_detailed_exceptions? rescue_with_handler(exception) || raise(exception) end end diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index f0c29825ba..de7b837ecc 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -21,6 +21,8 @@ module ActionController paths = app.config.paths options = app.config.action_controller + options.consider_all_requests_local ||= app.config.consider_all_requests_local + options.assets_dir ||= paths["public"].first options.javascripts_dir ||= paths["public/javascripts"].first options.stylesheets_dir ||= paths["public/stylesheets"].first diff --git a/actionpack/lib/action_controller/railties/paths.rb b/actionpack/lib/action_controller/railties/paths.rb index 699c44c62c..bbe63149ad 100644 --- a/actionpack/lib/action_controller/railties/paths.rb +++ b/actionpack/lib/action_controller/railties/paths.rb @@ -6,13 +6,14 @@ module ActionController define_method(:inherited) do |klass| super(klass) - if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) } - paths = namespace._railtie.paths["app/helpers"].existent + if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_helpers_paths) } + paths = namespace.railtie_helpers_paths else - paths = app.config.helpers_paths + paths = app.helpers_paths end klass.helpers_path = paths + if klass.superclass == ActionController::Base && ActionController::Base.include_all_helpers klass.helper :all end diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index a4ffd40a66..51cec41a34 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -243,10 +243,13 @@ module ActionDispatch @delete_cookies.clear end + mattr_accessor :always_write_cookie + self.always_write_cookie = false + private def write_cookie?(cookie) - @secure || !cookie[:secure] || defined?(Rails.env) && Rails.env.development? + @secure || !cookie[:secure] || always_write_cookie end end diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index d4208ca96e..6ded9dbfed 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -52,14 +52,9 @@ module ActionDispatch false end rescue Exception => e # YAML, XML or Ruby code block errors - logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}" + logger(env).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}" - raise - { "body" => request.raw_post, - "content_type" => request.content_mime_type, - "content_length" => request.content_length, - "exception" => "#{e.message} (#{e.class})", - "backtrace" => e.backtrace } + raise e end def content_type_from_legacy_post_data_format_header(env) @@ -73,8 +68,8 @@ module ActionDispatch nil end - def logger - defined?(Rails.logger) ? Rails.logger : Logger.new($stderr) + def logger(env) + env['action_dispatch.logger'] || Logger.new($stderr) end end end diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 2fa68c64c5..8dc2820d37 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -2,6 +2,7 @@ require 'active_support/core_ext/exception' require 'action_controller/metal/exceptions' require 'active_support/notifications' require 'action_dispatch/http/request' +require 'active_support/deprecation' module ActionDispatch # This middleware rescues any exception returned by the application and renders @@ -38,9 +39,9 @@ module ActionDispatch "application's log file and/or the web server's log file to find out what " << "went wrong.</body></html>"]] - def initialize(app, consider_all_requests_local = false) + def initialize(app, consider_all_requests_local = nil) + ActiveSupport::Deprecation.warn "Passing consider_all_requests_local option to ActionDispatch::ShowExceptions middleware no longer works" unless consider_all_requests_local.nil? @app = app - @consider_all_requests_local = consider_all_requests_local end def call(env) @@ -62,14 +63,13 @@ module ActionDispatch private def render_exception(env, exception) - log_error(exception) + log_error(env, exception) exception = original_exception(exception) - request = Request.new(env) - if @consider_all_requests_local || request.local? - rescue_action_locally(request, exception) + if env['action_dispatch.show_detailed_exceptions'] == true + rescue_action_diagnostics(env, exception) else - rescue_action_in_public(exception) + rescue_action_error_page(exception) end rescue Exception => failsafe_error $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}" @@ -78,9 +78,9 @@ module ActionDispatch # Render detailed diagnostics for unhandled exceptions rescued from # a controller action. - def rescue_action_locally(request, exception) + def rescue_action_diagnostics(env, exception) template = ActionView::Base.new([RESCUES_TEMPLATE_PATH], - :request => request, + :request => Request.new(env), :exception => exception, :application_trace => application_trace(exception), :framework_trace => framework_trace(exception), @@ -98,7 +98,7 @@ module ActionDispatch # it will first attempt to render the file at <tt>public/500.da.html</tt> # then attempt to render <tt>public/500.html</tt>. If none of them exist, # the body of the response will be left empty. - def rescue_action_in_public(exception) + def rescue_action_error_page(exception) status = status_code(exception) locale_path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale path = "#{public_path}/#{status}.html" @@ -124,14 +124,14 @@ module ActionDispatch defined?(Rails.public_path) ? Rails.public_path : 'public_path' end - def log_error(exception) - return unless logger + def log_error(env, exception) + return unless logger(env) ActiveSupport::Deprecation.silence do message = "\n#{exception.class} (#{exception.message}):\n" message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) message << " " << application_trace(exception).join("\n ") - logger.fatal("#{message}\n\n") + logger(env).fatal("#{message}\n\n") end end @@ -153,8 +153,12 @@ module ActionDispatch exception.backtrace end - def logger - defined?(Rails.logger) ? Rails.logger : Logger.new($stderr) + def logger(env) + env['action_dispatch.logger'] || stderr_logger + end + + def stderr_logger + Logger.new($stderr) end def original_exception(exception) diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 1af89858d1..f18ebabf29 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -10,10 +10,12 @@ module ActionDispatch 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 + + config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil? + ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie end end end diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 8fc8dc191b..39ba83fb9a 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -42,7 +42,7 @@ module ActionDispatch # url_for(:controller => 'users', # :action => 'new', # :message => 'Welcome!', - # :host => 'www.example.com') # Changed this. + # :host => 'www.example.com') # # => "http://www.example.com/users/new?message=Welcome%21" # # By default, all controllers and views have access to a special version of url_for, @@ -52,7 +52,7 @@ module ActionDispatch # # For convenience reasons, mailers provide a shortcut for ActionController::UrlFor#url_for. # So within mailers, you only have to type 'url_for' instead of 'ActionController::UrlFor#url_for' - # in full. However, mailers don't have hostname information, and what's why you'll still + # in full. However, mailers don't have hostname information, and that's why you'll still # have to specify the <tt>:host</tt> argument when generating URLs in mailers. # # diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb index 343153c8c5..41958c6559 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb @@ -68,6 +68,9 @@ module ActionView # Returns a stylesheet link tag for the sources specified as arguments. If # you don't specify an extension, <tt>.css</tt> will be appended automatically. # You can modify the link attributes by passing a hash as the last argument. + # For historical reasons, the 'media' attribute will always be present and defaults + # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to + # apply to all media types. # # ==== Examples # stylesheet_link_tag "style" # => diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb index 39c37b25dc..73824dc1f8 100644 --- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb +++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb @@ -32,7 +32,7 @@ module ActionView # app/views/posts/index.atom.builder: # atom_feed do |feed| # feed.title("My great blog!") - # feed.updated(@posts.first.created_at) + # feed.updated(@posts[0].created_at) if @posts.length > 0 # # @posts.each do |post| # feed.entry(post) do |entry| diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index d687866d0d..6c97d75922 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -158,6 +158,9 @@ module ActionView # * <tt>:url</tt> - The URL the form is submitted to. It takes the same # fields you pass to +url_for+ or +link_to+. In particular you may pass # here a named route directly as well. Defaults to the current action. + # * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of + # id attributes on form elements. The namespace attribute will be prefixed + # with underscore on the generate HTML id. # * <tt>:html</tt> - Optional HTML attributes for the form tag. # # Also note that +form_for+ doesn't create an exclusive scope. It's still @@ -385,7 +388,7 @@ module ActionView action, method = object.respond_to?(:persisted?) && object.persisted? ? [:edit, :put] : [:new, :post] options[:html].reverse_merge!( :class => as ? "#{as}_#{action}" : dom_class(object, action), - :id => as ? "#{as}_#{action}" : dom_id(object, action), + :id => as ? "#{as}_#{action}" : [options[:namespace], dom_id(object, action)].compact.join("_").presence, :method => method ) @@ -960,7 +963,7 @@ module ActionView end class InstanceTag - include Helpers::CaptureHelper, Context, Helpers::TagHelper, Helpers::FormTagHelper + include Helpers::TagHelper, Helpers::FormTagHelper attr_reader :object, :method_name, :object_name @@ -971,6 +974,7 @@ module ActionView def initialize(object_name, method_name, template_object, object = nil) @object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup @template_object = template_object + @object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]") @object = retrieve_object(object) @auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match @@ -989,10 +993,11 @@ module ActionView add_default_name_and_id_for_value(tag_value, name_and_id) options.delete("index") + options.delete("namespace") options["for"] ||= name_and_id["id"] if block_given? - label_tag(name_and_id["id"], options, &block) + @template_object.label_tag(name_and_id["id"], options, &block) else content = if text.blank? object_name.gsub!(/\[(.*)_attributes\]\[\d\]/, '.\1') @@ -1195,6 +1200,7 @@ module ActionView options["name"] ||= tag_name + (options['multiple'] ? '[]' : '') options["id"] = options.fetch("id"){ tag_id } end + options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence end def tag_name @@ -1253,7 +1259,7 @@ module ActionView @nested_child_index = {} @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc @parent_builder = options[:parent_builder] - @default_options = @options ? @options.slice(:index) : {} + @default_options = @options ? @options.slice(:index, :namespace) : {} if @object_name.to_s.match(/\[\]$/) if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:to_param) @auto_index = object.to_param @@ -1280,6 +1286,7 @@ module ActionView fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options? fields_options[:builder] ||= options[:builder] fields_options[:parent_builder] = self + fields_options[:namespace] = fields_options[:parent_builder].options[:namespace] case record_name when String, Symbol diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index ddf9b08b54..1ebe7f68f7 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -154,7 +154,7 @@ module Sprockets end def rewrite_extension(source, dir, ext) - if ext && File.extname(source).empty? + if ext && File.extname(source) != ".#{ext}" "#{source}.#{ext}" else source diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 24d071df39..cbb8968496 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -333,9 +333,9 @@ module ActionDispatch "#{FIXTURE_LOAD_PATH}/public" end - remove_method :logger + remove_method :stderr_logger # Silence logger - def logger + def stderr_logger nil end end diff --git a/actionpack/test/activerecord/polymorphic_routes_test.rb b/actionpack/test/activerecord/polymorphic_routes_test.rb index 20d11377f6..fc829aa6b4 100644 --- a/actionpack/test/activerecord/polymorphic_routes_test.rb +++ b/actionpack/test/activerecord/polymorphic_routes_test.rb @@ -34,10 +34,8 @@ module Blog set_table_name 'projects' end - def self._railtie - o = Object.new - def o.railtie_name; "blog" end - o + def self.use_relative_model_naming? + true end end diff --git a/actionpack/test/controller/show_exceptions_test.rb b/actionpack/test/controller/show_exceptions_test.rb new file mode 100644 index 0000000000..74067cb895 --- /dev/null +++ b/actionpack/test/controller/show_exceptions_test.rb @@ -0,0 +1,59 @@ +require 'abstract_unit' + +module ShowExceptions + class ShowExceptionsController < ActionController::Base + use ActionDispatch::ShowExceptions + + def boom + raise 'boom!' + end + end + + class ShowExceptionsTest < ActionDispatch::IntegrationTest + test 'show error page from a remote ip' do + @app = ShowExceptionsController.action(:boom) + self.remote_addr = '208.77.188.166' + get '/' + assert_equal "500 error fixture\n", body + end + + test 'show diagnostics from a local ip' do + @app = ShowExceptionsController.action(:boom) + ['127.0.0.1', '127.0.0.127', '::1', '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:1%0'].each do |ip_address| + self.remote_addr = ip_address + get '/' + assert_match(/boom/, body) + end + end + + test 'show diagnostics from a remote ip when consider_all_requests_local is true' do + ShowExceptionsController.any_instance.stubs(:consider_all_requests_local).returns(true) + @app = ShowExceptionsController.action(:boom) + self.remote_addr = '208.77.188.166' + get '/' + assert_match(/boom/, body) + end + end + + class ShowExceptionsOverridenController < ShowExceptionsController + private + + def show_detailed_exceptions? + params['detailed'] == '1' + end + end + + class ShowExceptionsOverridenTest < ActionDispatch::IntegrationTest + test 'show error page' do + @app = ShowExceptionsOverridenController.action(:boom) + get '/', {'detailed' => '0'} + assert_equal "500 error fixture\n", body + end + + test 'show diagnostics message' do + @app = ShowExceptionsOverridenController.action(:boom) + get '/', {'detailed' => '1'} + assert_match(/boom/, body) + end + end +end diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index 49da448001..3765b7eb44 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -210,8 +210,8 @@ class CookiesTest < ActionController::TestCase assert_equal({"user_name" => "david"}, @response.cookies) end - def test_setting_cookie_with_secure_in_development - Rails.env.stubs(:development?).returns(true) + def test_setting_cookie_with_secure_when_always_write_cookie_is_true + ActionDispatch::Cookies::CookieJar.any_instance.stubs(:always_write_cookie).returns(true) get :authenticate_with_secure assert_cookie_header "user_name=david; path=/; secure" assert_equal({"user_name" => "david"}, @response.cookies) diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index d854d55173..ad44b4b16a 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -32,13 +32,21 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest test "logs error if parsing unsuccessful" do with_test_routing do + output = StringIO.new + json = "[\"person]\": {\"name\": \"David\"}}" + post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => Logger.new(output)} + assert_response :error + output.rewind && err = output.read + assert err =~ /Error occurred while parsing request parameters/ + end + end + + test "occurring a parse error if parsing unsuccessful" do + with_test_routing do begin - $stderr = StringIO.new + $stderr = StringIO.new # suppress the log json = "[\"person]\": {\"name\": \"David\"}}" - post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => true} - assert_response :error - $stderr.rewind && err = $stderr.read - assert err =~ /Error occurred while parsing request parameters/ + assert_raise(MultiJson::DecodeError) { post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => false} } ensure $stderr = STDERR end diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb index 38453dfe48..d8fa751548 100644 --- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb @@ -54,13 +54,21 @@ class XmlParamsParsingTest < ActionDispatch::IntegrationTest test "logs error if parsing unsuccessful" do with_test_routing do + output = StringIO.new + xml = "<person><name>David</name><avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar></pineapple>" + post "/parse", xml, default_headers.merge('action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => Logger.new(output)) + assert_response :error + output.rewind && err = output.read + assert err =~ /Error occurred while parsing request parameters/ + end + end + + test "occurring a parse error if parsing unsuccessful" do + with_test_routing do begin - $stderr = StringIO.new - xml = "<person><name>David</name><avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar></pineapple>" - post "/parse", xml, default_headers.merge('action_dispatch.show_exceptions' => true) - assert_response :error - $stderr.rewind && err = $stderr.read - assert err =~ /Error occurred while parsing request parameters/ + $stderr = StringIO.new # suppress the log + xml = "<person><name>David</name></pineapple>" + assert_raise(REXML::ParseException) { post "/parse", xml, default_headers.merge('action_dispatch.show_exceptions' => false) } ensure $stderr = STDERR end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 42f6c7f79f..5875725b5d 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -2,32 +2,38 @@ require 'abstract_unit' class ShowExceptionsTest < ActionDispatch::IntegrationTest - Boomer = lambda do |env| - req = ActionDispatch::Request.new(env) - case req.path - when "/not_found" - raise ActionController::UnknownAction - when "/runtime_error" - raise RuntimeError - when "/method_not_allowed" - raise ActionController::MethodNotAllowed - when "/not_implemented" - raise ActionController::NotImplemented - when "/unprocessable_entity" - raise ActionController::InvalidAuthenticityToken - when "/not_found_original_exception" - raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new) - else - raise "puke!" + class Boomer + def initialize(detailed = false) + @detailed = detailed + end + + def call(env) + env['action_dispatch.show_detailed_exceptions'] = @detailed + req = ActionDispatch::Request.new(env) + case req.path + when "/not_found" + raise ActionController::UnknownAction + when "/runtime_error" + raise RuntimeError + when "/method_not_allowed" + raise ActionController::MethodNotAllowed + when "/not_implemented" + raise ActionController::NotImplemented + when "/unprocessable_entity" + raise ActionController::InvalidAuthenticityToken + when "/not_found_original_exception" + raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new) + else + raise "puke!" + end end end - ProductionApp = ActionDispatch::ShowExceptions.new(Boomer, false) - DevelopmentApp = ActionDispatch::ShowExceptions.new(Boomer, true) + ProductionApp = ActionDispatch::ShowExceptions.new(Boomer.new(false)) + DevelopmentApp = ActionDispatch::ShowExceptions.new(Boomer.new(true)) - test "rescue in public from a remote ip" do + test "rescue with error page when show_exceptions is false" do @app = ProductionApp - self.remote_addr = '208.77.188.166' get "/", {}, {'action_dispatch.show_exceptions' => true} assert_response 500 @@ -42,32 +48,28 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest assert_equal "", body end - test "rescue locally from a local request" do - @app = ProductionApp - ['127.0.0.1', '127.0.0.127', '::1', '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:1%0'].each do |ip_address| - self.remote_addr = ip_address + test "rescue with diagnostics message when show_exceptions is true" do + @app = DevelopmentApp - get "/", {}, {'action_dispatch.show_exceptions' => true} - assert_response 500 - assert_match(/puke/, body) + get "/", {}, {'action_dispatch.show_exceptions' => true} + assert_response 500 + assert_match(/puke/, body) - get "/not_found", {}, {'action_dispatch.show_exceptions' => true} - assert_response 404 - assert_match(/#{ActionController::UnknownAction.name}/, body) + get "/not_found", {}, {'action_dispatch.show_exceptions' => true} + assert_response 404 + assert_match(/#{ActionController::UnknownAction.name}/, body) - get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} - assert_response 405 - assert_match(/ActionController::MethodNotAllowed/, body) - end + get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} + assert_response 405 + assert_match(/ActionController::MethodNotAllowed/, body) end - test "localize public rescue message" do + test "localize rescue error page" do # Change locale old_locale, I18n.locale = I18n.locale, :da begin @app = ProductionApp - self.remote_addr = '208.77.188.166' get "/", {}, {'action_dispatch.show_exceptions' => true} assert_response 500 @@ -81,23 +83,6 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest end end - test "always rescue locally in development mode" do - @app = DevelopmentApp - self.remote_addr = '208.77.188.166' - - get "/", {}, {'action_dispatch.show_exceptions' => true} - assert_response 500 - assert_match(/puke/, body) - - get "/not_found", {}, {'action_dispatch.show_exceptions' => true} - assert_response 404 - assert_match(/#{ActionController::UnknownAction.name}/, body) - - get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} - assert_response 405 - assert_match(/ActionController::MethodNotAllowed/, body) - end - test "does not show filtered parameters" do @app = DevelopmentApp @@ -107,16 +92,15 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest assert_match(""foo"=>"[FILTERED]"", body) end - test "show registered original exception for wrapped exceptions when consider_all_requests_local is false" do + test "show registered original exception for wrapped exceptions when show_exceptions is false" do @app = ProductionApp - self.remote_addr = '208.77.188.166' get "/not_found_original_exception", {}, {'action_dispatch.show_exceptions' => true} assert_response 404 assert_match(/404 error/, body) end - test "show registered original exception for wrapped exceptions when consider_all_requests_local is true" do + test "show registered original exception for wrapped exceptions when show_exceptions is true" do @app = DevelopmentApp get "/not_found_original_exception", {}, {'action_dispatch.show_exceptions' => true} @@ -125,7 +109,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest end test "show the controller name in the diagnostics template when controller name is present" do - @app = ProductionApp + @app = DevelopmentApp get("/runtime_error", {}, { 'action_dispatch.show_exceptions' => true, 'action_dispatch.request.parameters' => { @@ -144,4 +128,11 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest get "/", {}, {'action_dispatch.show_exceptions' => true} assert_equal "text/html; charset=utf-8", response.headers["Content-Type"] end + + test 'uses logger from env' do + @app = ProductionApp + output = StringIO.new + get "/", {}, {'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => Logger.new(output)} + assert_match(/puke/, output.rewind && output.read) + end end diff --git a/actionpack/test/fixtures/test/_label_with_block.erb b/actionpack/test/fixtures/test/_label_with_block.erb new file mode 100644 index 0000000000..40117e594e --- /dev/null +++ b/actionpack/test/fixtures/test/_label_with_block.erb @@ -0,0 +1,4 @@ +<%= label 'post', 'message' do %> + Message + <%= text_field 'post', 'message' %> +<% end %> diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index 363403092b..f2362714d7 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -175,8 +175,8 @@ class HashBackedAuthor < Hash end module Blog - def self._railtie - self + def self.use_relative_model_naming? + true end class Post < Struct.new(:title, :id) diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 34486bb151..ad876df65d 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -230,6 +230,13 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal('<label for="post_title">The title, please:</label>', label(:post, :title) { "The title, please:" }) end + def test_label_with_block_in_erb + path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) + view_paths = ActionView::PathSet.new([path]) + view = ActionView::Base.new(view_paths) + assert_equal "<label for=\"post_message\">\n Message\n <input id=\"post_message\" name=\"post[message]\" size=\"30\" type=\"text\" />\n</label>", view.render("test/label_with_block") + end + def test_text_field assert_dom_equal( '<input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />', text_field("post", "title") @@ -740,7 +747,7 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end - def test_form_for_with_isolated_namespaced_model + def test_form_for_with_model_using_relative_model_naming form_for(@blog_post) do |f| concat f.text_field :title concat f.submit('Edit post') @@ -928,6 +935,82 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_form_for_with_namespace + form_for(@post, :namespace => 'namespace') do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do + "<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />" + + "<textarea name='post[body]' id='namespace_post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" + + "<input name='post[secret]' type='hidden' value='0' />" + + "<input name='post[secret]' checked='checked' type='checkbox' id='namespace_post_secret' value='1' />" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_namespace_with_label + form_for(@post, :namespace => 'namespace') do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do + "<label for='namespace_post_title'>Title</label>" + + "<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />" + end + + assert_dom_equal expected, output_buffer + end + + def test_two_form_for_with_namespace + form_for(@post, :namespace => 'namespace_1') do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + expected_1 = whole_form('/posts/123', 'namespace_1_edit_post_123', 'edit_post', 'put') do + "<label for='namespace_1_post_title'>Title</label>" + + "<input name='post[title]' size='30' type='text' id='namespace_1_post_title' value='Hello World' />" + end + + assert_dom_equal expected_1, output_buffer + + form_for(@post, :namespace => 'namespace_2') do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + expected_2 = whole_form('/posts/123', 'namespace_2_edit_post_123', 'edit_post', 'put') do + "<label for='namespace_2_post_title'>Title</label>" + + "<input name='post[title]' size='30' type='text' id='namespace_2_post_title' value='Hello World' />" + end + + assert_dom_equal expected_2, output_buffer + end + + def test_fields_for_with_namespace + @comment.body = 'Hello World' + form_for(@post, :namespace => 'namespace') do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.fields_for(@comment) { |c| + concat c.text_field(:body) + } + end + + expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do + "<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />" + + "<textarea name='post[body]' id='namespace_post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" + + "<input name='post[comment][body]' size='30' type='text' id='namespace_post_comment_body' value='Hello World' />" + end + + assert_dom_equal expected, output_buffer + end + def test_submit_with_object_as_new_record_and_locale_strings old_locale, I18n.locale = I18n.locale, :submit diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index db69f95130..26a504beb8 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -217,6 +217,9 @@ class SprocketsHelperTest < ActionView::TestCase assert_match %r{<script src="/assets/xmlhr-[0-9a-f]+.js\?body=1" type="text/javascript"></script>\n<script src="/assets/application-[0-9a-f]+.js\?body=1" type="text/javascript"></script>}, javascript_include_tag(:application, :debug => true) + assert_match %r{<script src="/assets/jquery.plugin.js" type="text/javascript"></script>}, + javascript_include_tag('jquery.plugin', :digest => false) + @config.assets.compile = true @config.assets.debug = true assert_match %r{<script src="/javascripts/application.js" type="text/javascript"></script>}, |