diff options
Diffstat (limited to 'actionpack/lib/action_controller/metal')
10 files changed, 131 insertions, 329 deletions
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index a90f798cd5..0e869e4e87 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -21,6 +21,8 @@ module ActionController class << self delegate :default_charset=, :to => "ActionDispatch::Response" + delegate :resources_path_names, :to => "ActionController::Routing::Routes" + delegate :resources_path_names=, :to => "ActionController::Routing::Routes" end # cattr_reader :protected_instance_variables @@ -29,15 +31,7 @@ module ActionController @variables_added @request_origin @url @parent_controller @action_name @before_filter_chain_aborted @_headers @_params - @_flash @_response) - - # Indicates whether or not optimise the generated named - # route helper methods - cattr_accessor :optimise_named_routes - self.optimise_named_routes = true - - cattr_accessor :resources_path_names - self.resources_path_names = { :new => 'new', :edit => 'edit' } + @_response) # Controls the resource action separator cattr_accessor :resource_action_separator diff --git a/actionpack/lib/action_controller/metal/filter_parameter_logging.rb b/actionpack/lib/action_controller/metal/filter_parameter_logging.rb index 59e200396a..0b1e1ee6ab 100644 --- a/actionpack/lib/action_controller/metal/filter_parameter_logging.rb +++ b/actionpack/lib/action_controller/metal/filter_parameter_logging.rb @@ -2,6 +2,8 @@ module ActionController module FilterParameterLogging extend ActiveSupport::Concern + INTERNAL_PARAMS = %w(controller action format _method only_path) + module ClassMethods # Replace sensitive parameter data from the request log. # Filters parameters that have any of the arguments as a substring. @@ -48,27 +50,19 @@ module ActionController filtered_params[key] = value end - filtered_params + filtered_params.except!(*INTERNAL_PARAMS) end protected :filter_parameters end - - protected - - # Overwrite log_process_action to include parameters information. - # If this method is invoked, it means logger is defined, so don't - # worry with such scenario here. - def log_process_action(controller) #:nodoc: - params = controller.send(:filter_parameters, controller.request.params) - logger.info " Parameters: #{params.inspect}" unless params.empty? - super - end end - INTERNAL_PARAMS = [:controller, :action, :format, :_method, :only_path] - protected + def append_info_to_payload(payload) + super + payload[:params] = filter_parameters(request.params) + end + def filter_parameters(params) params.dup.except!(*INTERNAL_PARAMS) end diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb index 25e25940a7..bd768b634e 100644 --- a/actionpack/lib/action_controller/metal/flash.rb +++ b/actionpack/lib/action_controller/metal/flash.rb @@ -1,187 +1,14 @@ module ActionController #:nodoc: - # The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed - # to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create - # action that sets <tt>flash[:notice] = "Successfully created"</tt> before redirecting to a display action that can - # then expose the flash to its template. Actually, that exposure is automatically done. Example: - # - # class PostsController < ActionController::Base - # def create - # # save post - # flash[:notice] = "Successfully created post" - # redirect_to @post - # end - # - # def show - # # doesn't need to assign the flash notice to the template, that's done automatically - # end - # end - # - # show.html.erb - # <% if flash[:notice] %> - # <div class="notice"><%= flash[:notice] %></div> - # <% end %> - # - # This example just places a string in the flash, but you can put any object in there. And of course, you can put as - # many as you like at a time too. Just remember: They'll be gone by the time the next action has been performed. - # - # See docs on the FlashHash class for more details about the flash. module Flash extend ActiveSupport::Concern included do + delegate :flash, :to => :request + delegate :alert, :notice, :to => "request.flash" helper_method :alert, :notice end - class FlashNow #:nodoc: - def initialize(flash) - @flash = flash - end - - def []=(k, v) - @flash[k] = v - @flash.discard(k) - v - end - - def [](k) - @flash[k] - end - end - - class FlashHash < Hash - def initialize #:nodoc: - super - @used = Set.new - end - - def []=(k, v) #:nodoc: - keep(k) - super - end - - def update(h) #:nodoc: - h.keys.each { |k| keep(k) } - super - end - - alias :merge! :update - - def replace(h) #:nodoc: - @used = Set.new - super - end - - # Sets a flash that will not be available to the next action, only to the current. - # - # flash.now[:message] = "Hello current action" - # - # This method enables you to use the flash as a central messaging system in your app. - # When you need to pass an object to the next action, you use the standard flash assign (<tt>[]=</tt>). - # When you need to pass an object to the current action, you use <tt>now</tt>, and your object will - # vanish when the current action is done. - # - # Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>. - def now - FlashNow.new(self) - end - - # Keeps either the entire current flash or a specific flash entry available for the next action: - # - # flash.keep # keeps the entire flash - # flash.keep(:notice) # keeps only the "notice" entry, the rest of the flash is discarded - def keep(k = nil) - use(k, false) - end - - # Marks the entire flash or a single flash entry to be discarded by the end of the current action: - # - # flash.discard # discard the entire flash at the end of the current action - # flash.discard(:warning) # discard only the "warning" entry at the end of the current action - def discard(k = nil) - use(k) - end - - # Mark for removal entries that were kept, and delete unkept ones. - # - # This method is called automatically by filters, so you generally don't need to care about it. - def sweep #:nodoc: - keys.each do |k| - unless @used.include?(k) - @used << k - else - delete(k) - @used.delete(k) - end - end - - # clean up after keys that could have been left over by calling reject! or shift on the flash - (@used - keys).each{ |k| @used.delete(k) } - end - - def store(session) - return if self.empty? - session["flash"] = self - end - - private - # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods - # use() # marks the entire flash as used - # use('msg') # marks the "msg" entry as used - # use(nil, false) # marks the entire flash as unused (keeps it around for one more action) - # use('msg', false) # marks the "msg" entry as unused (keeps it around for one more action) - # Returns the single value for the key you asked to be marked (un)used or the FlashHash itself - # if no key is passed. - def use(key = nil, used = true) - Array(key || keys).each { |k| used ? @used << k : @used.delete(k) } - return key ? self[key] : self - end - end - - # Access the contents of the flash. Use <tt>flash["notice"]</tt> to - # read a notice you put there or <tt>flash["notice"] = "hello"</tt> - # to put a new one. - def flash #:doc: - unless @_flash - @_flash = session["flash"] || FlashHash.new - @_flash.sweep - end - - @_flash - end - - # Convenience accessor for flash[:alert] - def alert - flash[:alert] - end - - # Convenience accessor for flash[:alert]= - def alert=(message) - flash[:alert] = message - end - - # Convenience accessor for flash[:notice] - def notice - flash[:notice] - end - - # Convenience accessor for flash[:notice]= - def notice=(message) - flash[:notice] = message - end - protected - def process_action(method_name) - @_flash = nil - super - @_flash.store(session) if @_flash - @_flash = nil - end - - def reset_session - super - @_flash = nil - end - def redirect_to(options = {}, response_status_and_flash = {}) #:doc: if alert = response_status_and_flash.delete(:alert) flash[:alert] = alert diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb index c82d9cf369..37be8b3999 100644 --- a/actionpack/lib/action_controller/metal/head.rb +++ b/actionpack/lib/action_controller/metal/head.rb @@ -1,6 +1,7 @@ module ActionController module Head - include UrlFor + extend ActiveSupport::Concern + include ActionController::UrlFor # Return a response that has no content (merely headers). The options # argument is interpreted to be a hash of header names and values. diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb new file mode 100644 index 0000000000..7222b7b2fa --- /dev/null +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -0,0 +1,102 @@ +require 'abstract_controller/logger' + +module ActionController + # Adds instrumentation to several ends in ActionController::Base. It also provides + # some hooks related with process_action, this allows an ORM like ActiveRecord + # and/or DataMapper to plug in ActionController and show related information. + # + # Check ActiveRecord::Railties::ControllerRuntime for an example. + module Instrumentation + extend ActiveSupport::Concern + + included do + include AbstractController::Logger + end + + attr_internal :view_runtime + + def process_action(action, *args) + ActiveSupport::Notifications.instrument("action_controller.process_action") do |payload| + result = super + payload[:controller] = self.class.name + payload[:action] = self.action_name + payload[:formats] = request.formats.map(&:to_s) + payload[:remote_ip] = request.remote_ip + payload[:method] = request.method + payload[:status] = response.status + payload[:request_uri] = request.request_uri rescue "unknown" + append_info_to_payload(payload) + result + end + end + + def render(*args, &block) + if logger + render_output = nil + + self.view_runtime = cleanup_view_runtime do + Benchmark.ms { render_output = super } + end + + render_output + else + super + end + end + + def send_file(path, options={}) + ActiveSupport::Notifications.instrument("action_controller.send_file", + options.merge(:path => path)) do + super + end + end + + def send_data(data, options = {}) + ActiveSupport::Notifications.instrument("action_controller.send_data", options) do + super + end + end + + def redirect_to(*args) + ActiveSupport::Notifications.instrument("action_controller.redirect_to") do |payload| + result = super + payload[:status] = self.status + payload[:location] = self.location + result + end + end + + protected + + # A hook which allows you to clean up any time taken into account in + # views wrongly, like database querying time. + # + # def cleanup_view_runtime + # super - time_taken_in_something_expensive + # end + # + # :api: plugin + def cleanup_view_runtime #:nodoc: + yield + end + + # Everytime after an action is processed, this method is invoked + # with the payload, so you can add more information. + # :api: plugin + def append_info_to_payload(payload) #:nodoc: + payload[:view_runtime] = view_runtime + end + + module ClassMethods + # A hook which allows other frameworks to log what happened during + # controller process action. This method should return an array + # with the messages to be added. + # :api: plugin + def log_process_action(payload) #:nodoc: + messages, view_runtime = [], payload[:view_runtime] + messages << ("Views: %.1fms" % view_runtime.to_f) if view_runtime + messages + end + end + end +end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb deleted file mode 100644 index 4f4370e5f0..0000000000 --- a/actionpack/lib/action_controller/metal/logger.rb +++ /dev/null @@ -1,89 +0,0 @@ -require 'abstract_controller/logger' - -module ActionController - # Adds instrumentation to <tt>process_action</tt> and a <tt>log_event</tt> method - # responsible to log events from ActiveSupport::Notifications. This module handles - # :process_action and :render_template events but allows any other module to hook - # into log_event and provide its own logging facilities (as in ActionController::Caching). - module Logger - extend ActiveSupport::Concern - - included do - include AbstractController::Logger - end - - attr_internal :view_runtime - - def process_action(action) - ActiveSupport::Notifications.instrument(:process_action, :controller => self, :action => action) do - super - end - end - - def render(*args, &block) - if logger - render_output = nil - - self.view_runtime = cleanup_view_runtime do - Benchmark.ms { render_output = super } - end - - render_output - else - super - end - end - - # If you want to remove any time taken into account in :view_runtime - # wrongly, you can do it here: - # - # def cleanup_view_runtime - # super - time_taken_in_something_expensive - # end - # - # :api: plugin - def cleanup_view_runtime #:nodoc: - yield - end - - module ClassMethods - # This is the hook invoked by ActiveSupport::Notifications.subscribe. - # If you need to log any event, overwrite the method and do it here. - def log_event(name, before, after, instrumenter_id, payload) #:nodoc: - if name == :process_action - duration = [(after - before) * 1000, 0.01].max - controller = payload[:controller] - request = controller.request - - logger.info "\n\nProcessed #{controller.class.name}##{payload[:action]} " \ - "to #{request.formats} (for #{request.remote_ip} at #{before.to_s(:db)}) " \ - "[#{request.method.to_s.upcase}]" - - log_process_action(controller) - - message = "Completed in %.0fms" % duration - message << " | #{controller.response.status}" - message << " [#{request.request_uri rescue "unknown"}]" - - logger.info(message) - elsif name == :render_template - # TODO Make render_template logging work if you are using just ActionView - duration = (after - before) * 1000 - message = "Rendered #{payload[:identifier]}" - message << " within #{payload[:layout]}" if payload[:layout] - message << (" (%.1fms)" % duration) - logger.info(message) - end - end - - protected - - # A hook which allows logging what happened during controller process action. - # :api: plugin - def log_process_action(controller) #:nodoc: - view_runtime = controller.send :view_runtime - logger.info(" View runtime: %.1fms" % view_runtime.to_f) if view_runtime - end - end - end -end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 468c5f4fae..4c02677729 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -215,7 +215,10 @@ module ActionController #:nodoc: # a proc to it. # def respond_with(*resources, &block) - if response = retrieve_response_from_mimes([], &block) + raise "In order to use respond_with, first you need to declare the formats your " << + "controller responds to in the class level" if mimes_for_respond_to.empty? + + if response = retrieve_response_from_mimes(&block) options = resources.extract_options! options.merge!(:default_response => response) (options.delete(:responder) || responder).call(self, resources, options) @@ -246,9 +249,9 @@ module ActionController #:nodoc: # Collects mimes and return the response for the negotiated format. Returns # nil if :not_acceptable was sent to the client. # - def retrieve_response_from_mimes(mimes, &block) + def retrieve_response_from_mimes(mimes=nil, &block) collector = Collector.new { default_render } - mimes = collect_mimes_from_class_level if mimes.empty? + mimes ||= collect_mimes_from_class_level mimes.each { |mime| collector.send(mime) } block.call(collector) if block_given? diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index 7a2f9a6fc5..faf0589fd2 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -9,7 +9,9 @@ module ActionController module Redirecting extend ActiveSupport::Concern + include AbstractController::Logger + include ActionController::UrlFor # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: # @@ -55,8 +57,6 @@ module ActionController self.status = _extract_redirect_to_status(options, response_status) self.location = _compute_redirect_to_location(options) self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>" - - logger.info("Redirected to #{location}") if logger && logger.info? end private diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 288b5d7c99..8f03b8bb17 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -88,13 +88,11 @@ module ActionController #:nodoc: @performed_render = false if options[:x_sendfile] - logger.info "Sending #{X_SENDFILE_HEADER} header #{path}" if logger head options[:status], X_SENDFILE_HEADER => path else if options[:stream] # TODO : Make render :text => proc {} work with the new base render :status => options[:status], :text => Proc.new { |response, output| - logger.info "Streaming file #{path}" unless logger.nil? len = options[:buffer_size] || 4096 File.open(path, 'rb') do |file| while buf = file.read(len) @@ -103,7 +101,6 @@ module ActionController #:nodoc: end } else - logger.info "Sending file #{path}" unless logger.nil? File.open(path, 'rb') { |file| render :status => options[:status], :text => file.read } end end @@ -141,7 +138,6 @@ module ActionController #:nodoc: # data to the browser, then use <tt>render :text => proc { ... }</tt> # instead. See ActionController::Base#render for more information. def send_data(data, options = {}) #:doc: - logger.info "Sending data #{options[:filename]}" if logger send_file_headers! options.merge(:length => data.bytesize) render :status => options[:status], :text => data end diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 8c3810ebcb..73feacb872 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -2,40 +2,14 @@ module ActionController module UrlFor extend ActiveSupport::Concern - include RackDelegation + include AbstractController::UrlFor + include ActionController::RackDelegation - # Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in - # the form of a hash, just like the one you would use for url_for directly. Example: - # - # def default_url_options(options) - # { :project => @project.active? ? @project.url_name : "unknown" } - # end - # - # As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the - # urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set - # by this method. - def default_url_options(options = nil) - end - - def rewrite_options(options) #:nodoc: - if defaults = default_url_options(options) - defaults.merge(options) - else - options - end - end + protected - def url_for(options = {}) - options ||= {} - case options - when String - options - when Hash - @url ||= UrlRewriter.new(request, params) - @url.rewrite(rewrite_options(options)) - else - polymorphic_url(options) - end + def _url_rewriter + return ActionController::UrlRewriter unless request + @_url_rewriter ||= ActionController::UrlRewriter.new(request, params) end end end |