diff options
Diffstat (limited to 'actionpack/lib/action_controller')
10 files changed, 83 insertions, 38 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 1eda6e3f04..0facf7066d 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -22,7 +22,7 @@ module ActionController #:nodoc: attr_reader :allowed_methods def initialize(*allowed_methods) - super("Only #{allowed_methods.to_sentence} requests are allowed.") + super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.") @allowed_methods = allowed_methods end @@ -908,12 +908,14 @@ module ActionController #:nodoc: end options = extra_options + elsif !options.is_a?(Hash) + extra_options[:partial] = options + options = extra_options end layout = pick_layout(options) response.layout = layout.path_without_format_and_extension if layout logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout - layout = layout.path_without_format_and_extension if layout if content_type = options[:content_type] response.content_type = content_type.to_s @@ -1101,7 +1103,6 @@ module ActionController #:nodoc: end response.redirected_to = options - logger.info("Redirected to #{options}") if logger && logger.info? case options # The scheme name consist of a letter followed by any combination of @@ -1124,6 +1125,7 @@ module ActionController #:nodoc: def redirect_to_full_url(url, status) raise DoubleRenderError if performed? + logger.info("Redirected to #{url}") if logger && logger.info? response.redirect(url, interpret_status(status)) @performed_redirect = true end @@ -1133,6 +1135,11 @@ module ActionController #:nodoc: # request is considered stale and should be generated from scratch. Otherwise, # it's fresh and we don't need to generate anything and a reply of "304 Not Modified" is sent. # + # Parameters: + # * <tt>:etag</tt> + # * <tt>:last_modified</tt> + # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). + # # Example: # # def show @@ -1153,20 +1160,34 @@ module ActionController #:nodoc: # Sets the etag, last_modified, or both on the response and renders a # "304 Not Modified" response if the request is already fresh. # + # Parameters: + # * <tt>:etag</tt> + # * <tt>:last_modified</tt> + # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). + # # Example: # # def show # @article = Article.find(params[:id]) - # fresh_when(:etag => @article, :last_modified => @article.created_at.utc) + # fresh_when(:etag => @article, :last_modified => @article.created_at.utc, :public => true) # end # # This will render the show template if the request isn't sending a matching etag or # If-Modified-Since header and just a "304 Not Modified" response if there's a match. + # def fresh_when(options) - options.assert_valid_keys(:etag, :last_modified) + options.assert_valid_keys(:etag, :last_modified, :public) response.etag = options[:etag] if options[:etag] response.last_modified = options[:last_modified] if options[:last_modified] + + if options[:public] + cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip } + cache_control.delete("private") + cache_control.delete("no-cache") + cache_control << "public" + response.headers["Cache-Control"] = cache_control.join(', ') + end if request.fresh?(response) head :not_modified @@ -1178,15 +1199,26 @@ module ActionController #:nodoc: # # Examples: # expires_in 20.minutes - # expires_in 3.hours, :private => false - # expires in 3.hours, 'max-stale' => 5.hours, :private => nil, :public => true + # expires_in 3.hours, :public => true + # expires in 3.hours, 'max-stale' => 5.hours, :public => true # # This method will overwrite an existing Cache-Control header. # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities. def expires_in(seconds, options = {}) #:doc: - cache_options = { 'max-age' => seconds, 'private' => true }.symbolize_keys.merge!(options.symbolize_keys) - cache_options.delete_if { |k,v| v.nil? or v == false } - cache_control = cache_options.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"} + cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip } + + cache_control << "max-age=#{seconds}" + cache_control.delete("no-cache") + if options[:public] + cache_control.delete("private") + cache_control << "public" + else + cache_control << "private" + end + + # This allows for additional headers to be passed through like 'max-stale' => 5.hours + cache_control += options.symbolize_keys.reject{|k,v| k == :public || k == :private }.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"} + response.headers["Cache-Control"] = cache_control.join(', ') end @@ -1298,7 +1330,7 @@ module ActionController #:nodoc: rescue ActionView::MissingTemplate => e # Was the implicit template missing, or was it another template? if e.path == default_template_name - raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller + raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence(:locale => :en)}", caller else raise e end diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index ec40b5c4e6..07931e4a4a 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -13,7 +13,6 @@ module ActionController end if defined?(ActiveRecord) - after_dispatch :checkin_connections to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers } end @@ -115,11 +114,5 @@ module ActionController def flush_logger Base.logger.flush end - - def checkin_connections - # Don't return connection (and peform implicit rollback) if this request is a part of integration test - return if @env.key?("rack.test") - ActiveRecord::Base.clear_active_connections! - end end end diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb index a0db7acf72..6ec0c1b304 100644 --- a/actionpack/lib/action_controller/layout.rb +++ b/actionpack/lib/action_controller/layout.rb @@ -198,7 +198,7 @@ module ActionController #:nodoc: # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard. - def active_layout(passed_layout = nil) + def active_layout(passed_layout = nil, options = {}) layout = passed_layout || default_layout return layout if layout.respond_to?(:render) @@ -207,21 +207,23 @@ module ActionController #:nodoc: when Proc then layout.call(self) else layout end - - find_layout(active_layout, @template.template_format) if active_layout + + find_layout(active_layout, default_template_format, options[:html_fallback]) if active_layout end private def default_layout #:nodoc: - layout = self.class.read_inheritable_attribute(:layout) unless default_template_format == :js + layout = self.class.read_inheritable_attribute(:layout) return layout unless self.class.read_inheritable_attribute(:auto_layout) find_layout(layout, default_template_format) rescue ActionView::MissingTemplate nil end - def find_layout(layout, *formats) #:nodoc: - view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", *formats) + def find_layout(layout, format, html_fallback=false) #:nodoc: + view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", format, html_fallback) + rescue ActionView::MissingTemplate + raise if Mime::Type.lookup_by_extension(format.to_s).html? end def pick_layout(options) @@ -232,7 +234,7 @@ module ActionController #:nodoc: when NilClass, TrueClass active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name) else - active_layout(layout) + active_layout(layout, :html_fallback => true) end else active_layout if action_has_layout? && candidate_for_layout?(options) @@ -258,7 +260,12 @@ module ActionController #:nodoc: template = options[:template] || default_template(options[:action]) if options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty? begin - !self.view_paths.find_template(template, default_template_format).exempt_from_layout? + template_object = self.view_paths.find_template(template, default_template_format) + # this restores the behavior from 2.2.2, where response.template.template_format was reset + # to :html for :js requests with a matching html template. + # see v2.2.2, ActionView::Base, lines 328-330 + @real_format = :html if response.template.template_format == :js && template_object.format == "html" + !template_object.exempt_from_layout? rescue ActionView::MissingTemplate true end @@ -268,7 +275,7 @@ module ActionController #:nodoc: end def default_template_format - response.template.template_format + @real_format || response.template.template_format end end end diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index 0e95cfc147..2cabab9ec8 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -32,7 +32,7 @@ module ActionController # <tt>:get</tt>. If the request \method is not listed in the HTTP_METHODS # constant above, an UnknownHttpMethod exception is raised. def request_method - @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}") + @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") end # Returns the HTTP request \method used for action processing as a diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 3af21967df..0a89c4b3d5 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -91,7 +91,7 @@ module ActionController end def shallow_path_prefix - @shallow_path_prefix ||= "#{path_prefix unless @options[:shallow]}" + @shallow_path_prefix ||= @options[:shallow] ? @options[:namespace].try(:sub, /\/$/, '') : path_prefix end def member_path @@ -103,7 +103,7 @@ module ActionController end def shallow_name_prefix - @shallow_name_prefix ||= "#{name_prefix unless @options[:shallow]}" + @shallow_name_prefix ||= @options[:shallow] ? @options[:namespace].try(:gsub, /\//, '_') : name_prefix end def nesting_name_prefix @@ -670,7 +670,12 @@ module ActionController when "show", "edit"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements(require_id)) when "update"; default_options.merge(add_conditions_for(resource.conditions, method || :put)).merge(resource.requirements(require_id)) when "destroy"; default_options.merge(add_conditions_for(resource.conditions, method || :delete)).merge(resource.requirements(require_id)) - else default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements) + else + if method.nil? || resource.member_methods.nil? || resource.member_methods[method.to_sym].nil? + default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements) + else + resource.member_methods[method.to_sym].include?(action) ? default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements(require_id)) : default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements) + end end end end diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb index a2141a77dc..c0eb61340b 100644 --- a/actionpack/lib/action_controller/routing.rb +++ b/actionpack/lib/action_controller/routing.rb @@ -267,7 +267,7 @@ module ActionController module Routing SEPARATORS = %w( / . ? ) - HTTP_METHODS = [:get, :head, :post, :put, :delete] + HTTP_METHODS = [:get, :head, :post, :put, :delete, :options] ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb index 44d759444a..d9590c88b8 100644 --- a/actionpack/lib/action_controller/routing/builder.rb +++ b/actionpack/lib/action_controller/routing/builder.rb @@ -159,7 +159,8 @@ module ActionController path = "/#{path}" unless path[0] == ?/ path = "#{path}/" unless path[-1] == ?/ - path = "/#{options[:path_prefix].to_s.gsub(/^\//,'')}#{path}" if options[:path_prefix] + prefix = options[:path_prefix].to_s.gsub(/^\//,'') + path = "/#{prefix}#{path}" unless prefix.blank? segments = segments_for_route_path(path) defaults, requirements, conditions = divide_route_options(segments, options) diff --git a/actionpack/lib/action_controller/routing/recognition_optimisation.rb b/actionpack/lib/action_controller/routing/recognition_optimisation.rb index ebc553512f..9bfebff0c0 100644 --- a/actionpack/lib/action_controller/routing/recognition_optimisation.rb +++ b/actionpack/lib/action_controller/routing/recognition_optimisation.rb @@ -98,7 +98,6 @@ module ActionController if Array === item i += 1 start = (i == 1) - final = (i == list.size) tag, sub = item if tag == :dynamic body += padding + "#{start ? 'if' : 'elsif'} true\n" diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index 129e87c139..4f936d51d2 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -3,7 +3,11 @@ module ActionController class Segment #:nodoc: RESERVED_PCHAR = ':@&=+$,;' SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}" - UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze + if RUBY_VERSION >= '1.9' + UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze + else + UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze + end # TODO: Convert :is_optional accessor to read only attr_accessor :is_optional @@ -314,13 +318,17 @@ module ActionController end def regexp_chunk - '(\.[^/?\.]+)?' + '/|(\.[^/?\.]+)?' end def to_s '(.:format)?' end - + + def extract_value + "#{local_name} = options[:#{key}] && options[:#{key}].to_s.downcase" + end + #the value should not include the period (.) def match_extraction(next_capture) %[ diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb index 376bb87409..e2c49c284f 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb @@ -556,7 +556,7 @@ module HTML end # Attribute value. - next if statement.sub!(/^\[\s*([[:alpha:]][\w\-]*)\s*((?:[~|^$*])?=)?\s*('[^']*'|"[^*]"|[^\]]*)\s*\]/) do |match| + next if statement.sub!(/^\[\s*([[:alpha:]][\w\-:]*)\s*((?:[~|^$*])?=)?\s*('[^']*'|"[^*]"|[^\]]*)\s*\]/) do |match| name, equality, value = $1, $2, $3 if value == "?" value = values.shift |