diff options
Diffstat (limited to 'actionpack/lib')
15 files changed, 187 insertions, 161 deletions
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/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 970236a05a..7947e9d393 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -374,10 +374,6 @@ module ActionDispatch # # Matches any request starting with 'path' # match 'path' => 'c#a', :anchor => false def match(path, options=nil) - mapping = Mapping.new(@set, @scope, path, options || {}) - app, conditions, requirements, defaults, as, anchor = mapping.to_route - @set.add_route(app, conditions, requirements, defaults, as, anchor) - self end # Mount a Rack-based application to be used within the application. @@ -867,8 +863,6 @@ module ActionDispatch CANONICAL_ACTIONS = %w(index create new show update destroy) class Resource #:nodoc: - DEFAULT_ACTIONS = [:index, :create, :new, :show, :update, :destroy, :edit] - attr_reader :controller, :path, :options def initialize(entities, options = {}) @@ -880,7 +874,7 @@ module ActionDispatch end def default_actions - self.class::DEFAULT_ACTIONS + [:index, :create, :new, :show, :update, :destroy, :edit] end def actions @@ -934,16 +928,17 @@ module ActionDispatch end class SingletonResource < Resource #:nodoc: - DEFAULT_ACTIONS = [:show, :create, :update, :destroy, :new, :edit] - def initialize(entities, options) super - @as = nil @controller = (options[:controller] || plural).to_s @as = options[:as] end + def default_actions + [:show, :create, :update, :destroy, :new, :edit] + end + def plural @plural ||= name.to_s.pluralize end @@ -991,7 +986,7 @@ module ActionDispatch return self end - resource_scope(SingletonResource.new(resources.pop, options)) do + resource_scope(:resource, SingletonResource.new(resources.pop, options)) do yield if block_given? collection do @@ -1122,7 +1117,7 @@ module ActionDispatch return self end - resource_scope(Resource.new(resources.pop, options)) do + resource_scope(:resources, Resource.new(resources.pop, options)) do yield if block_given? collection do @@ -1245,32 +1240,44 @@ module ActionDispatch parent_resource.instance_of?(Resource) && @scope[:shallow] end - def match(*args) - options = args.extract_options!.dup - options[:anchor] = true unless options.key?(:anchor) - - if args.length > 1 - args.each { |path| match(path, options.dup) } - return self + def match(path, *rest) + if rest.empty? && Hash === path + options = path + path, to = options.find { |name, value| name.is_a?(String) } + options[:to] = to + options.delete(path) + paths = [path] + else + options = rest.pop || {} + paths = [path] + rest end - on = options.delete(:on) - if VALID_ON_OPTIONS.include?(on) - args.push(options) - return send(on){ match(*args) } - elsif on + options[:anchor] = true unless options.key?(:anchor) + + if options[:on] && !VALID_ON_OPTIONS.include?(options[:on]) raise ArgumentError, "Unknown scope #{on.inspect} given to :on" end - if @scope[:scope_level] == :resources - args.push(options) - return nested { match(*args) } - elsif @scope[:scope_level] == :resource - args.push(options) - return member { match(*args) } + paths.each { |_path| decomposed_match(_path, options.dup) } + self + end + + def decomposed_match(path, options) # :nodoc: + if on = options.delete(:on) + send(on) { decomposed_match(path, options) } + else + case @scope[:scope_level] + when :resources + nested { decomposed_match(path, options) } + when :resource + member { decomposed_match(path, options) } + else + add_route(path, options) + end end + end - action = args.first + def add_route(action, options) # :nodoc: path = path_for_action(action, options.delete(:path)) if action.to_s =~ /^[\w\/]+$/ @@ -1279,13 +1286,15 @@ module ActionDispatch action = nil end - if options.key?(:as) && !options[:as] + if !options.fetch(:as) { true } options.delete(:as) else options[:as] = name_for_action(options[:as], action) end - super(path, options) + mapping = Mapping.new(@set, @scope, path, options) + app, conditions, requirements, defaults, as, anchor = mapping.to_route + @set.add_route(app, conditions, requirements, defaults, as, anchor) end def root(options={}) @@ -1341,7 +1350,7 @@ module ActionDispatch end def scope_action_options? #:nodoc: - @scope[:options].is_a?(Hash) && (@scope[:options][:only] || @scope[:options][:except]) + @scope[:options] && (@scope[:options][:only] || @scope[:options][:except]) end def scope_action_options #:nodoc: @@ -1349,11 +1358,11 @@ module ActionDispatch end def resource_scope? #:nodoc: - @scope[:scope_level].in?([:resource, :resources]) + [:resource, :resources].include? @scope[:scope_level] end def resource_method_scope? #:nodoc: - @scope[:scope_level].in?([:collection, :member, :new]) + [:collection, :member, :new].include? @scope[:scope_level] end def with_exclusive_scope @@ -1378,8 +1387,8 @@ module ActionDispatch @scope[:scope_level_resource] = old_resource end - def resource_scope(resource) #:nodoc: - with_scope_level(resource.is_a?(SingletonResource) ? :resource : :resources, resource) do + def resource_scope(kind, resource) #:nodoc: + with_scope_level(kind, resource) do scope(parent_resource.resource_scope) do yield end @@ -1387,10 +1396,12 @@ module ActionDispatch end def nested_options #:nodoc: - {}.tap do |options| - options[:as] = parent_resource.member_name - options[:constraints] = { "#{parent_resource.singular}_id".to_sym => id_constraint } if id_constraint? - end + options = { :as => parent_resource.member_name } + options[:constraints] = { + :"#{parent_resource.singular}_id" => id_constraint + } if id_constraint? + + options end def id_constraint? #:nodoc: @@ -1466,19 +1477,6 @@ module ActionDispatch end end - module Shorthand #:nodoc: - def match(path, *rest) - if rest.empty? && Hash === path - options = path - path, to = options.find { |name, value| name.is_a?(String) } - options.merge!(:to => to).delete(path) - super(path, options) - else - super - end - end - end - def initialize(set) #:nodoc: @set = set @scope = { :path_names => @set.resources_path_names } @@ -1489,7 +1487,6 @@ module ActionDispatch include Redirection include Scoping include Resources - include Shorthand end end end diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index 804991ad5f..330400e139 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -2,6 +2,54 @@ require 'action_dispatch/http/request' module ActionDispatch module Routing + class Redirect # :nodoc: + attr_reader :status, :block + + def initialize(status, block) + @status = status + @block = block + end + + def call(env) + req = Request.new(env) + + uri = URI.parse(path(req.symbolized_path_parameters, req)) + uri.scheme ||= req.scheme + uri.host ||= req.host + uri.port ||= req.port unless req.standard_port? + + body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>) + + headers = { + 'Location' => uri.to_s, + 'Content-Type' => 'text/html', + 'Content-Length' => body.length.to_s + } + + [ status, headers, [body] ] + end + + def path(params, request) + block.call params, request + end + end + + class OptionRedirect < Redirect # :nodoc: + alias :options :block + + def path(params, request) + url_options = { + :protocol => request.protocol, + :host => request.host, + :port => request.optional_port, + :path => request.path, + :params => request.query_parameters + }.merge options + + ActionDispatch::Http::URL.url_for url_options + end + end + module Redirection # Redirect any path to another path: @@ -40,71 +88,27 @@ module ActionDispatch options = args.last.is_a?(Hash) ? args.pop : {} status = options.delete(:status) || 301 + return OptionRedirect.new(status, options) if options.any? + path = args.shift - path_proc = if path.is_a?(String) - proc { |params| (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % params) } - elsif options.any? - options_proc(options) - elsif path.respond_to?(:call) - proc { |params, request| path.call(params, request) } - elsif block - block - else - raise ArgumentError, "redirection argument not supported" - end + block = lambda { |params, request| + (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % params) + } if String === path - redirection_proc(status, path_proc) - end + block = path if path.respond_to? :call - private - - def options_proc(options) - proc do |params, request| - path = if options[:path].nil? - request.path - elsif params.empty? || !options[:path].match(/%\{\w*\}/) - options.delete(:path) - else - (options.delete(:path) % params) - end - - default_options = { - :protocol => request.protocol, - :host => request.host, - :port => request.optional_port, - :path => path, - :params => request.query_parameters - } - - ActionDispatch::Http::URL.url_for(options.reverse_merge(default_options)) - end + # :FIXME: remove in Rails 4.0 + if block && block.respond_to?(:arity) && block.arity < 2 + msg = "redirect blocks with arity of #{block.arity} are deprecated. Your block must take 2 parameters: the environment, and a request object" + ActiveSupport::Deprecation.warn msg + block = lambda { |params, _| block.call(params) } end - def redirection_proc(status, path_proc) - lambda do |env| - req = Request.new(env) - - params = [req.symbolized_path_parameters] - params << req if path_proc.arity > 1 - - uri = URI.parse(path_proc.call(*params)) - uri.scheme ||= req.scheme - uri.host ||= req.host - uri.port ||= req.port unless req.standard_port? - - body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>) - - headers = { - 'Location' => uri.to_s, - 'Content-Type' => 'text/html', - 'Content-Length' => body.length.to_s - } - - [ status, headers, [body] ] - end - end + raise ArgumentError, "redirection argument not supported" unless block + Redirect.new status, block + end end end -end
\ No newline at end of file +end 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/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 42726f888c..cc74eff53a 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -48,7 +48,9 @@ module ActionView if html_safe_translation_key?(key) html_safe_options = options.dup options.except(*I18n::RESERVED_KEYS).each do |name, value| - html_safe_options[name] = ERB::Util.html_escape(value.to_s) + unless name == :count && value.is_a?(Numeric) + html_safe_options[name] = ERB::Util.html_escape(value.to_s) + end end translation = I18n.translate(scope_key_by_partial(key), html_safe_options) diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 15cb9d0f76..54a0ba96ff 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -366,8 +366,13 @@ module ActionView path = if object.respond_to?(:to_partial_path) object.to_partial_path else - ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_partial_path directly instead." - object.class.model_name.partial_path + klass = object.class + if klass.respond_to?(:model_name) + ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_partial_path directly instead." + klass.model_name.partial_path + else + raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object that returns a valid partial path.") + end end @partial_names[path] ||= path.dup.tap do |object_path| 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 |