From fa575973b1ad5adb7115a18c4c1c7c31500e73b2 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 17 Dec 2009 16:37:11 -0800 Subject: Added alert/notice from 2-3-stable and refactored redirect_to into just living in Redirector [DHH] --- actionpack/lib/action_controller/base.rb | 66 ----------------- actionpack/lib/action_controller/metal/flash.rb | 41 +++++++++++ .../lib/action_controller/metal/redirector.rb | 86 ++++++++++++++++++++-- 3 files changed, 122 insertions(+), 71 deletions(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 48bfbab215..e49be371a6 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -106,71 +106,5 @@ module ActionController options = _normalize_options(action, options, &blk) super(options) end - - # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: - # - # * Hash - The URL will be generated by calling url_for with the +options+. - # * Record - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. - # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. - # * String not containing a protocol - The current protocol and host is prepended to the string. - # * :back - Back to the page that issued the request. Useful for forms that are triggered from multiple places. - # Short-hand for redirect_to(request.env["HTTP_REFERER"]) - # - # Examples: - # redirect_to :action => "show", :id => 5 - # redirect_to post - # redirect_to "http://www.rubyonrails.org" - # redirect_to "/images/screenshot.jpg" - # redirect_to articles_url - # redirect_to :back - # - # The redirection happens as a "302 Moved" header unless otherwise specified. - # - # Examples: - # redirect_to post_url(@post), :status=>:found - # redirect_to :action=>'atom', :status=>:moved_permanently - # redirect_to post_url(@post), :status=>301 - # redirect_to :action=>'atom', :status=>302 - # - # When using redirect_to :back, if there is no referrer, - # RedirectBackError will be raised. You may specify some fallback - # behavior for this case by rescuing RedirectBackError. - def redirect_to(options = {}, response_status = {}) #:doc: - raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? - - status = if options.is_a?(Hash) && options.key?(:status) - _interpret_status(options.delete(:status)) - elsif response_status.key?(:status) - _interpret_status(response_status[:status]) - else - 302 - end - - url = case options - # The scheme name consist of a letter followed by any combination of - # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") - # characters; and is terminated by a colon (":"). - when %r{^\w[\w\d+.-]*:.*} - options - when String - request.protocol + request.host_with_port + options - when :back - raise RedirectBackError unless refer = request.headers["Referer"] - refer - else - url_for(options) - end - - super(url, status) - end - - private - def _interpret_status(status) - if status.is_a?(Symbol) - (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500) - else - status.to_i - end - end end end diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb index 9d08ed6081..ae343444e2 100644 --- a/actionpack/lib/action_controller/metal/flash.rb +++ b/actionpack/lib/action_controller/metal/flash.rb @@ -30,6 +30,10 @@ module ActionController #:nodoc: include Session + included do + helper_method :alert, :notice + end + class FlashNow #:nodoc: def initialize(flash) @flash = flash @@ -147,6 +151,27 @@ module ActionController #:nodoc: @_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 @@ -159,5 +184,21 @@ module ActionController #:nodoc: super @_flash = nil end + + def redirect_to(options = {}, response_status_and_flash = {}) #:doc: + if alert = response_status_and_flash.delete(:alert) + flash[:alert] = alert + end + + if notice = response_status_and_flash.delete(:notice) + flash[:notice] = notice + end + + if other_flashes = response_status_and_flash.delete(:flash) + flash.update(other_flashes) + end + + super(options, response_status_and_flash) + end end end diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb index b55f5e7bfc..a7bd5ee981 100644 --- a/actionpack/lib/action_controller/metal/redirector.rb +++ b/actionpack/lib/action_controller/metal/redirector.rb @@ -11,12 +11,88 @@ module ActionController extend ActiveSupport::Concern include AbstractController::Logger - def redirect_to(url, status) #:doc: + # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: + # + # * Hash - The URL will be generated by calling url_for with the +options+. + # * Record - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. + # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. + # * String not containing a protocol - The current protocol and host is prepended to the string. + # * :back - Back to the page that issued the request. Useful for forms that are triggered from multiple places. + # Short-hand for redirect_to(request.env["HTTP_REFERER"]) + # + # Examples: + # redirect_to :action => "show", :id => 5 + # redirect_to post + # redirect_to "http://www.rubyonrails.org" + # redirect_to "/images/screenshot.jpg" + # redirect_to articles_url + # redirect_to :back + # + # The redirection happens as a "302 Moved" header unless otherwise specified. + # + # Examples: + # redirect_to post_url(@post), :status => :found + # redirect_to :action=>'atom', :status => :moved_permanently + # redirect_to post_url(@post), :status => 301 + # redirect_to :action=>'atom', :status => 302 + # + # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names + # +alert+ and +notice+ as well as a general purpose +flash+ bucket. + # + # Examples: + # redirect_to post_url(@post), :alert => "Watch it, mister!" + # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road" + # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id } + # redirect_to { :action=>'atom' }, :alert => "Something serious happened" + # + # When using redirect_to :back, if there is no referrer, + # RedirectBackError will be raised. You may specify some fallback + # behavior for this case by rescuing RedirectBackError. + def redirect_to(options = {}, response_status = {}) #:doc: + raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? raise AbstractController::DoubleRenderError if response_body - logger.info("Redirected to #{url}") if logger && logger.info? - self.status = status - self.location = url.gsub(/[\r\n]/, '') - self.response_body = "You are being redirected." + + self.status = _extract_redirect_to_status(options, response_status) + self.location = _compute_redirect_to_location(options) + self.response_body = "You are being redirected." + + logger.info("Redirected to #{location}") if logger && logger.info? end + + private + def _extract_redirect_to_status(options, response_status) + status = if options.is_a?(Hash) && options.key?(:status) + _interpret_status(options.delete(:status)) + elsif response_status.key?(:status) + _interpret_status(response_status[:status]) + else + 302 + end + end + + def _compute_redirect_to_location(options) + case options + # The scheme name consist of a letter followed by any combination of + # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") + # characters; and is terminated by a colon (":"). + when %r{^\w[\w\d+.-]*:.*} + options + when String + request.protocol + request.host_with_port + options + when :back + raise RedirectBackError unless refer = request.headers["Referer"] + refer + else + url_for(options) + end.gsub(/[\r\n]/, '') + end + + def _interpret_status(status) + if status.is_a?(Symbol) + (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500) + else + status.to_i + end + end end end -- cgit v1.2.3 From c06aff0a7e42868e9788d6cefe5ce49e93cbf45b Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 20 Dec 2009 14:33:13 -0800 Subject: Added cookies.permanent, cookies.signed, and cookies.permanent.signed accessor for common cookie actions [DHH] --- actionpack/lib/action_controller/metal/cookies.rb | 168 +++++++++++++++++----- 1 file changed, 130 insertions(+), 38 deletions(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/metal/cookies.rb b/actionpack/lib/action_controller/metal/cookies.rb index 6855ca1478..8db665e929 100644 --- a/actionpack/lib/action_controller/metal/cookies.rb +++ b/actionpack/lib/action_controller/metal/cookies.rb @@ -50,56 +50,148 @@ module ActionController #:nodoc: included do helper_method :cookies + cattr_accessor :cookie_verifier_secret end - protected - # Returns the cookie container, which operates as described above. - def cookies - @cookies ||= CookieJar.build(request, response) + protected + # Returns the cookie container, which operates as described above. + def cookies + @cookies ||= CookieJar.build(request, response) + end end - end - class CookieJar < Hash #:nodoc: - def self.build(request, response) - new.tap do |hash| - hash.update(request.cookies) - hash.response = response + class CookieJar < Hash #:nodoc: + def self.build(request, response) + new.tap do |hash| + hash.update(request.cookies) + hash.response = response + end end - end - attr_accessor :response + attr_accessor :response - # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists. - def [](name) - super(name.to_s) - end + # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists. + def [](name) + super(name.to_s) + end + + # Sets the cookie named +name+. The second argument may be the very cookie + # value, or a hash of options as documented above. + def []=(key, options) + if options.is_a?(Hash) + options.symbolize_keys! + value = options[:value] + else + value = options + options = { :value => value } + end - # Sets the cookie named +name+. The second argument may be the very cookie - # value, or a hash of options as documented above. - def []=(key, options) - if options.is_a?(Hash) + super(key.to_s, value) + + options[:path] ||= "/" + response.set_cookie(key, options) + end + + # Removes the cookie on the client machine by setting the value to an empty string + # and setting its expiration date into the past. Like []=, you can pass in + # an options hash to delete cookies with extra data such as a :path. + def delete(key, options = {}) options.symbolize_keys! - value = options[:value] - else - value = options - options = { :value => value } + options[:path] ||= "/" + value = super(key.to_s) + response.delete_cookie(key, options) + value end - super(key.to_s, value) - - options[:path] ||= "/" - response.set_cookie(key, options) + # Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example: + # + # cookies.permanent[:prefers_open_id] = true + # # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT + # + # This jar is only meant for writing. You'll read permanent cookies through the regular accessor. + # + # This jar allows chaining with the signed jar as well, so you can set permanent, signed cookies. Examples: + # + # cookies.permanent.signed[:remember_me] = current_user.id + # # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT + def permanent + @permanent ||= PermanentCookieJar.new(self) + end + + # Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from + # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed + # cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will + # be raised. + # + # This jar requires that you set a suitable secret for the verification on ActionController::Base.cookie_verifier_secret. + # + # Example: + # + # cookies.signed[:discount] = 45 + # # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/ + # + # cookies.signed[:discount] # => 45 + def signed + @signed ||= SignedCookieJar.new(self) + end end - - # Removes the cookie on the client machine by setting the value to an empty string - # and setting its expiration date into the past. Like []=, you can pass in - # an options hash to delete cookies with extra data such as a :path. - def delete(key, options = {}) - options.symbolize_keys! - options[:path] ||= "/" - value = super(key.to_s) - response.delete_cookie(key, options) - value + + class PermanentCookieJar < CookieJar #:nodoc: + def initialize(parent_jar) + @parent_jar = parent_jar + end + + def []=(key, options) + if options.is_a?(Hash) + options.symbolize_keys! + else + options = { :value => options } + end + + options[:expires] = 20.years.from_now + @parent_jar[key] = options + end + + def signed + @signed ||= SignedCookieJar.new(self) + end + + def controller + @parent_jar.controller + end + + def method_missing(method, *arguments, &block) + @parent_jar.send(method, *arguments, &block) + end end + + class SignedCookieJar < CookieJar #:nodoc: + def initialize(parent_jar) + unless ActionController::Base.cookie_verifier_secret + raise "You must set ActionController::Base.cookie_verifier_secret to use signed cookies" + end + + @parent_jar = parent_jar + @verifier = ActiveSupport::MessageVerifier.new(ActionController::Base.cookie_verifier_secret) + end + + def [](name) + @verifier.verify(@parent_jar[name]) + end + + def []=(key, options) + if options.is_a?(Hash) + options.symbolize_keys! + options[:value] = @verifier.generate(options[:value]) + else + options = { :value => @verifier.generate(options) } + end + + @parent_jar[key] = options + end + + def method_missing(method, *arguments, &block) + @parent_jar.send(method, *arguments, &block) + end end end -- cgit v1.2.3 From 83f4d86a9330533ec9af21ba18b4ab28011b8981 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 20 Dec 2009 17:15:31 -0800 Subject: Rename the RenderingController module to just plain Rendering --- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/metal/layouts.rb | 2 +- .../lib/action_controller/metal/rendering.rb | 57 ++++++++++++++++++++++ .../metal/rendering_controller.rb | 57 ---------------------- .../lib/action_controller/metal/streaming.rb | 2 +- .../lib/action_controller/metal/verification.rb | 2 +- 6 files changed, 61 insertions(+), 61 deletions(-) create mode 100644 actionpack/lib/action_controller/metal/rendering.rb delete mode 100644 actionpack/lib/action_controller/metal/rendering_controller.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index e49be371a6..ee10584548 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -9,7 +9,7 @@ module ActionController include ActionController::HideActions include ActionController::UrlFor include ActionController::Redirector - include ActionController::RenderingController + include ActionController::Rendering include ActionController::RenderOptions::All include ActionController::Layouts include ActionController::ConditionalGet diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb index cc7088248a..f44498a884 100644 --- a/actionpack/lib/action_controller/metal/layouts.rb +++ b/actionpack/lib/action_controller/metal/layouts.rb @@ -158,7 +158,7 @@ module ActionController module Layouts extend ActiveSupport::Concern - include ActionController::RenderingController + include ActionController::Rendering include AbstractController::Layouts module ClassMethods diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb new file mode 100644 index 0000000000..20eb524e50 --- /dev/null +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -0,0 +1,57 @@ +module ActionController + module Rendering + extend ActiveSupport::Concern + + included do + include AbstractController::Rendering + include AbstractController::LocalizedCache + end + + def process_action(*) + self.formats = request.formats.map {|x| x.to_sym} + super + end + + def render(options) + super + self.content_type ||= options[:_template].mime_type.to_s + response_body + end + + def render_to_body(options) + _process_options(options) + + if options.key?(:partial) + options[:partial] = action_name if options[:partial] == true + options[:_details] = {:formats => formats} + end + + super + end + + private + def _prefix + controller_path + end + + def _determine_template(options) + if (options.keys & [:partial, :file, :template, :text, :inline]).empty? + options[:_template_name] ||= options[:action] + options[:_prefix] = _prefix + end + + super + end + + def format_for_text + formats.first + end + + def _process_options(options) + status, content_type, location = options.values_at(:status, :content_type, :location) + self.status = status if status + self.content_type = content_type if content_type + self.headers["Location"] = url_for(location) if location + end + end +end diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering_controller.rb deleted file mode 100644 index 237299cd30..0000000000 --- a/actionpack/lib/action_controller/metal/rendering_controller.rb +++ /dev/null @@ -1,57 +0,0 @@ -module ActionController - module RenderingController - extend ActiveSupport::Concern - - included do - include AbstractController::RenderingController - include AbstractController::LocalizedCache - end - - def process_action(*) - self.formats = request.formats.map {|x| x.to_sym} - super - end - - def render(options) - super - self.content_type ||= options[:_template].mime_type.to_s - response_body - end - - def render_to_body(options) - _process_options(options) - - if options.key?(:partial) - options[:partial] = action_name if options[:partial] == true - options[:_details] = {:formats => formats} - end - - super - end - - private - def _prefix - controller_path - end - - def _determine_template(options) - if (options.keys & [:partial, :file, :template, :text, :inline]).empty? - options[:_template_name] ||= options[:action] - options[:_prefix] = _prefix - end - - super - end - - def format_for_text - formats.first - end - - def _process_options(options) - status, content_type, location = options.values_at(:status, :content_type, :location) - self.status = status if status - self.content_type = content_type if content_type - self.headers["Location"] = url_for(location) if location - end - end -end diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 43c661bef4..288b5d7c99 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -4,7 +4,7 @@ module ActionController #:nodoc: module Streaming extend ActiveSupport::Concern - include ActionController::RenderingController + include ActionController::Rendering DEFAULT_SEND_FILE_OPTIONS = { :type => 'application/octet-stream'.freeze, diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb index 500cced539..cbd169b641 100644 --- a/actionpack/lib/action_controller/metal/verification.rb +++ b/actionpack/lib/action_controller/metal/verification.rb @@ -2,7 +2,7 @@ module ActionController #:nodoc: module Verification #:nodoc: extend ActiveSupport::Concern - include AbstractController::Callbacks, Session, Flash, RenderingController + include AbstractController::Callbacks, Session, Flash, Rendering # This module provides a class-level method for specifying that certain # actions are guarded against being called without certain prerequisites -- cgit v1.2.3 From 9b41e1e4d8b9d159254dc4ad4bbd3207f1b49eb5 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 20 Dec 2009 17:25:13 -0800 Subject: Renamed Redirector to Redirecting (its a module, not a class) --- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/metal.rb | 2 +- .../lib/action_controller/metal/redirecting.rb | 98 ++++++++++++++++++++++ .../lib/action_controller/metal/redirector.rb | 98 ---------------------- 4 files changed, 100 insertions(+), 100 deletions(-) create mode 100644 actionpack/lib/action_controller/metal/redirecting.rb delete mode 100644 actionpack/lib/action_controller/metal/redirector.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ee10584548..ec64cc1a39 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -8,7 +8,7 @@ module ActionController include ActionController::Helpers include ActionController::HideActions include ActionController::UrlFor - include ActionController::Redirector + include ActionController::Redirecting include ActionController::Rendering include ActionController::RenderOptions::All include ActionController::Layouts diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 60b3f9a89b..a1d857d2ce 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -58,7 +58,7 @@ module ActionController # Basic implementations for content_type=, location=, and headers are # provided to reduce the dependency on the RackConvenience module - # in Renderer and Redirector. + # in Rendering and Redirecting. def content_type=(type) headers["Content-Type"] = type.to_s diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb new file mode 100644 index 0000000000..d101f920e3 --- /dev/null +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -0,0 +1,98 @@ +module ActionController + class RedirectBackError < AbstractController::Error #:nodoc: + DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].' + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + + module Redirecting + extend ActiveSupport::Concern + include AbstractController::Logger + + # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: + # + # * Hash - The URL will be generated by calling url_for with the +options+. + # * Record - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. + # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. + # * String not containing a protocol - The current protocol and host is prepended to the string. + # * :back - Back to the page that issued the request. Useful for forms that are triggered from multiple places. + # Short-hand for redirect_to(request.env["HTTP_REFERER"]) + # + # Examples: + # redirect_to :action => "show", :id => 5 + # redirect_to post + # redirect_to "http://www.rubyonrails.org" + # redirect_to "/images/screenshot.jpg" + # redirect_to articles_url + # redirect_to :back + # + # The redirection happens as a "302 Moved" header unless otherwise specified. + # + # Examples: + # redirect_to post_url(@post), :status => :found + # redirect_to :action=>'atom', :status => :moved_permanently + # redirect_to post_url(@post), :status => 301 + # redirect_to :action=>'atom', :status => 302 + # + # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names + # +alert+ and +notice+ as well as a general purpose +flash+ bucket. + # + # Examples: + # redirect_to post_url(@post), :alert => "Watch it, mister!" + # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road" + # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id } + # redirect_to { :action=>'atom' }, :alert => "Something serious happened" + # + # When using redirect_to :back, if there is no referrer, + # RedirectBackError will be raised. You may specify some fallback + # behavior for this case by rescuing RedirectBackError. + def redirect_to(options = {}, response_status = {}) #:doc: + raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? + raise AbstractController::DoubleRenderError if response_body + + self.status = _extract_redirect_to_status(options, response_status) + self.location = _compute_redirect_to_location(options) + self.response_body = "You are being redirected." + + logger.info("Redirected to #{location}") if logger && logger.info? + end + + private + def _extract_redirect_to_status(options, response_status) + status = if options.is_a?(Hash) && options.key?(:status) + _interpret_status(options.delete(:status)) + elsif response_status.key?(:status) + _interpret_status(response_status[:status]) + else + 302 + end + end + + def _compute_redirect_to_location(options) + case options + # The scheme name consist of a letter followed by any combination of + # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") + # characters; and is terminated by a colon (":"). + when %r{^\w[\w\d+.-]*:.*} + options + when String + request.protocol + request.host_with_port + options + when :back + raise RedirectBackError unless refer = request.headers["Referer"] + refer + else + url_for(options) + end.gsub(/[\r\n]/, '') + end + + def _interpret_status(status) + if status.is_a?(Symbol) + (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500) + else + status.to_i + end + end + end +end diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb deleted file mode 100644 index a7bd5ee981..0000000000 --- a/actionpack/lib/action_controller/metal/redirector.rb +++ /dev/null @@ -1,98 +0,0 @@ -module ActionController - class RedirectBackError < AbstractController::Error #:nodoc: - DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].' - - def initialize(message = nil) - super(message || DEFAULT_MESSAGE) - end - end - - module Redirector - extend ActiveSupport::Concern - include AbstractController::Logger - - # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: - # - # * Hash - The URL will be generated by calling url_for with the +options+. - # * Record - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. - # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. - # * String not containing a protocol - The current protocol and host is prepended to the string. - # * :back - Back to the page that issued the request. Useful for forms that are triggered from multiple places. - # Short-hand for redirect_to(request.env["HTTP_REFERER"]) - # - # Examples: - # redirect_to :action => "show", :id => 5 - # redirect_to post - # redirect_to "http://www.rubyonrails.org" - # redirect_to "/images/screenshot.jpg" - # redirect_to articles_url - # redirect_to :back - # - # The redirection happens as a "302 Moved" header unless otherwise specified. - # - # Examples: - # redirect_to post_url(@post), :status => :found - # redirect_to :action=>'atom', :status => :moved_permanently - # redirect_to post_url(@post), :status => 301 - # redirect_to :action=>'atom', :status => 302 - # - # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names - # +alert+ and +notice+ as well as a general purpose +flash+ bucket. - # - # Examples: - # redirect_to post_url(@post), :alert => "Watch it, mister!" - # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road" - # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id } - # redirect_to { :action=>'atom' }, :alert => "Something serious happened" - # - # When using redirect_to :back, if there is no referrer, - # RedirectBackError will be raised. You may specify some fallback - # behavior for this case by rescuing RedirectBackError. - def redirect_to(options = {}, response_status = {}) #:doc: - raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? - raise AbstractController::DoubleRenderError if response_body - - self.status = _extract_redirect_to_status(options, response_status) - self.location = _compute_redirect_to_location(options) - self.response_body = "You are being redirected." - - logger.info("Redirected to #{location}") if logger && logger.info? - end - - private - def _extract_redirect_to_status(options, response_status) - status = if options.is_a?(Hash) && options.key?(:status) - _interpret_status(options.delete(:status)) - elsif response_status.key?(:status) - _interpret_status(response_status[:status]) - else - 302 - end - end - - def _compute_redirect_to_location(options) - case options - # The scheme name consist of a letter followed by any combination of - # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") - # characters; and is terminated by a colon (":"). - when %r{^\w[\w\d+.-]*:.*} - options - when String - request.protocol + request.host_with_port + options - when :back - raise RedirectBackError unless refer = request.headers["Referer"] - refer - else - url_for(options) - end.gsub(/[\r\n]/, '') - end - - def _interpret_status(status) - if status.is_a?(Symbol) - (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500) - else - status.to_i - end - end - end -end -- cgit v1.2.3 From 0f8a5c7954bfc134f46eeb72c4cc8744825cbb5a Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 20 Dec 2009 20:00:04 -0600 Subject: Merge Session stuff into RackConvenience --- actionpack/lib/action_controller/base.rb | 1 - actionpack/lib/action_controller/metal/flash.rb | 10 ++-- .../action_controller/metal/rack_convenience.rb | 1 + .../metal/request_forgery_protection.rb | 32 +++++----- actionpack/lib/action_controller/metal/session.rb | 15 ----- .../lib/action_controller/metal/verification.rb | 70 +++++++++++----------- 6 files changed, 56 insertions(+), 73 deletions(-) delete mode 100644 actionpack/lib/action_controller/metal/session.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ec64cc1a39..d24c01c983 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -26,7 +26,6 @@ module ActionController include ActionController::Compatibility include ActionController::Cookies - include ActionController::Session include ActionController::Flash include ActionController::Verification include ActionController::RequestForgeryProtection diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb index ae343444e2..581ff6109e 100644 --- a/actionpack/lib/action_controller/metal/flash.rb +++ b/actionpack/lib/action_controller/metal/flash.rb @@ -28,8 +28,6 @@ module ActionController #:nodoc: module Flash extend ActiveSupport::Concern - include Session - included do helper_method :alert, :notice end @@ -155,7 +153,7 @@ module ActionController #:nodoc: def alert flash[:alert] end - + # Convenience accessor for flash[:alert]= def alert=(message) flash[:alert] = message @@ -165,7 +163,7 @@ module ActionController #:nodoc: def notice flash[:notice] end - + # Convenience accessor for flash[:notice]= def notice=(message) flash[:notice] = message @@ -193,11 +191,11 @@ module ActionController #:nodoc: if notice = response_status_and_flash.delete(:notice) flash[:notice] = notice end - + if other_flashes = response_status_and_flash.delete(:flash) flash.update(other_flashes) end - + super(options, response_status_and_flash) end end diff --git a/actionpack/lib/action_controller/metal/rack_convenience.rb b/actionpack/lib/action_controller/metal/rack_convenience.rb index 131d20114d..f0837c10e8 100644 --- a/actionpack/lib/action_controller/metal/rack_convenience.rb +++ b/actionpack/lib/action_controller/metal/rack_convenience.rb @@ -3,6 +3,7 @@ module ActionController extend ActiveSupport::Concern included do + delegate :session, :reset_session, :to => "@_request" delegate :headers, :status=, :location=, :content_type=, :status, :location, :content_type, :to => "@_response" attr_internal :request diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 173df79ee7..2826b1e34c 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -5,7 +5,7 @@ module ActionController #:nodoc: module RequestForgeryProtection extend ActiveSupport::Concern - include AbstractController::Helpers, Session + include AbstractController::Helpers included do # Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+ @@ -19,31 +19,31 @@ module ActionController #:nodoc: helper_method :form_authenticity_token helper_method :protect_against_forgery? end - - # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current - # web application, not a forged link from another site, is done by embedding a token based on a random + + # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current + # web application, not a forged link from another site, is done by embedding a token based on a random # string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated - # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript - # requests are checked, so this will not protect your XML API (presumably you'll have a different - # authentication scheme there anyway). Also, GET requests are not protected as these should be + # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript + # requests are checked, so this will not protect your XML API (presumably you'll have a different + # authentication scheme there anyway). Also, GET requests are not protected as these should be # idempotent anyway. # # This is turned on with the protect_from_forgery method, which will check the token and raise an - # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the + # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the # error message in production by editing public/422.html. A call to this method in ApplicationController is # generated by default in post-Rails 2.0 applications. # - # The token parameter is named authenticity_token by default. If you are generating an HTML form - # manually (without the use of Rails' form_for, form_tag or other helpers), you have to - # include a hidden field named like that and set its value to what is returned by + # The token parameter is named authenticity_token by default. If you are generating an HTML form + # manually (without the use of Rails' form_for, form_tag or other helpers), you have to + # include a hidden field named like that and set its value to what is returned by # form_authenticity_token. # - # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails + # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails # 1.x, add this to config/environments/test.rb: # # # Disable request forgery protection in test environment # config.action_controller.allow_forgery_protection = false - # + # # == Learn more about CSRF (Cross-Site Request Forgery) attacks # # Here are some resources: @@ -52,11 +52,11 @@ module ActionController #:nodoc: # # Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application. # There are a few guidelines you should follow: - # + # # * Keep your GET requests safe and idempotent. More reading material: # * http://www.xml.com/pub/a/2002/04/24/deviant.html # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 - # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look + # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look # for "Expires: at end of session" # module ClassMethods @@ -92,7 +92,7 @@ module ActionController #:nodoc: # * is it a GET request? Gets should be safe and idempotent # * Does the form_authenticity_token match the given token value from the params? def verified_request? - !protect_against_forgery? || request.forgery_whitelisted? || + !protect_against_forgery? || request.forgery_whitelisted? || form_authenticity_token == params[request_forgery_protection_token] end diff --git a/actionpack/lib/action_controller/metal/session.rb b/actionpack/lib/action_controller/metal/session.rb deleted file mode 100644 index bcedd6e1c7..0000000000 --- a/actionpack/lib/action_controller/metal/session.rb +++ /dev/null @@ -1,15 +0,0 @@ -module ActionController - module Session - extend ActiveSupport::Concern - - include RackConvenience - - def session - @_request.session - end - - def reset_session - @_request.reset_session - end - end -end diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb index cbd169b641..bce942b588 100644 --- a/actionpack/lib/action_controller/metal/verification.rb +++ b/actionpack/lib/action_controller/metal/verification.rb @@ -2,7 +2,7 @@ module ActionController #:nodoc: module Verification #:nodoc: extend ActiveSupport::Concern - include AbstractController::Callbacks, Session, Flash, Rendering + include AbstractController::Callbacks, Flash, Rendering # This module provides a class-level method for specifying that certain # actions are guarded against being called without certain prerequisites @@ -35,7 +35,7 @@ module ActionController #:nodoc: # :add_flash => { "alert" => "Failed to create your message" }, # :redirect_to => :category_url # - # Note that these prerequisites are not business rules. They do not examine + # Note that these prerequisites are not business rules. They do not examine # the content of the session or the parameters. That level of validation should # be encapsulated by your domain model or helper methods in the controller. module ClassMethods @@ -43,40 +43,40 @@ module ActionController #:nodoc: # the user is redirected to a different action. The +options+ parameter # is a hash consisting of the following key/value pairs: # - # :params:: - # a single key or an array of keys that must be in the params + # :params:: + # a single key or an array of keys that must be in the params # hash in order for the action(s) to be safely called. - # :session:: - # a single key or an array of keys that must be in the session + # :session:: + # a single key or an array of keys that must be in the session # in order for the action(s) to be safely called. - # :flash:: - # a single key or an array of keys that must be in the flash in order + # :flash:: + # a single key or an array of keys that must be in the flash in order # for the action(s) to be safely called. - # :method:: - # a single key or an array of keys--any one of which must match the - # current request method in order for the action(s) to be safely called. - # (The key should be a symbol: :get or :post, for + # :method:: + # a single key or an array of keys--any one of which must match the + # current request method in order for the action(s) to be safely called. + # (The key should be a symbol: :get or :post, for # example.) - # :xhr:: - # true/false option to ensure that the request is coming from an Ajax - # call or not. - # :add_flash:: - # a hash of name/value pairs that should be merged into the session's + # :xhr:: + # true/false option to ensure that the request is coming from an Ajax + # call or not. + # :add_flash:: + # a hash of name/value pairs that should be merged into the session's # flash if the prerequisites cannot be satisfied. - # :add_headers:: - # a hash of name/value pairs that should be merged into the response's + # :add_headers:: + # a hash of name/value pairs that should be merged into the response's # headers hash if the prerequisites cannot be satisfied. - # :redirect_to:: - # the redirection parameters to be used when redirecting if the - # prerequisites cannot be satisfied. You can redirect either to named + # :redirect_to:: + # the redirection parameters to be used when redirecting if the + # prerequisites cannot be satisfied. You can redirect either to named # route or to the action in some controller. - # :render:: + # :render:: # the render parameters to be used when the prerequisites cannot be satisfied. - # :only:: - # only apply this verification to the actions specified in the associated + # :only:: + # only apply this verification to the actions specified in the associated # array (may also be a single value). - # :except:: - # do not apply this verification to the actions specified in the associated + # :except:: + # do not apply this verification to the actions specified in the associated # array (may also be a single value). def verify(options={}) before_filter :only => options[:only], :except => options[:except] do @@ -94,31 +94,31 @@ module ActionController #:nodoc: apply_remaining_actions(options) unless performed? end end - + def prereqs_invalid?(options) # :nodoc: - verify_presence_of_keys_in_hash_flash_or_params(options) || - verify_method(options) || + verify_presence_of_keys_in_hash_flash_or_params(options) || + verify_method(options) || verify_request_xhr_status(options) end - + def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc: [*options[:params] ].find { |v| v && params[v.to_sym].nil? } || [*options[:session]].find { |v| session[v].nil? } || [*options[:flash] ].find { |v| flash[v].nil? } end - + def verify_method(options) # :nodoc: [*options[:method]].all? { |v| request.method != v.to_sym } if options[:method] end - + def verify_request_xhr_status(options) # :nodoc: request.xhr? != options[:xhr] unless options[:xhr].nil? end - + def apply_redirect_to(redirect_to_option) # :nodoc: (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option end - + def apply_remaining_actions(options) # :nodoc: case when options[:render] ; render(options[:render]) -- cgit v1.2.3 From 29c8a43056f40759a8c64cbcbd4e71d4283b233d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 20 Dec 2009 20:05:26 -0600 Subject: Rename RackConvenience => RackDelegation --- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/metal.rb | 6 ++--- .../lib/action_controller/metal/conditional_get.rb | 2 +- actionpack/lib/action_controller/metal/cookies.rb | 2 +- .../action_controller/metal/rack_convenience.rb | 28 ---------------------- .../lib/action_controller/metal/rack_delegation.rb | 28 ++++++++++++++++++++++ actionpack/lib/action_controller/metal/testing.rb | 2 +- actionpack/lib/action_controller/metal/url_for.rb | 2 +- 8 files changed, 36 insertions(+), 36 deletions(-) delete mode 100644 actionpack/lib/action_controller/metal/rack_convenience.rb create mode 100644 actionpack/lib/action_controller/metal/rack_delegation.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index d24c01c983..6eda653cb2 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -13,7 +13,7 @@ module ActionController include ActionController::RenderOptions::All include ActionController::Layouts include ActionController::ConditionalGet - include ActionController::RackConvenience + include ActionController::RackDelegation include ActionController::Benchmarking include ActionController::Configuration diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index a1d857d2ce..8433be2320 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -45,7 +45,7 @@ module ActionController # The details below can be overridden to support a specific # Request and Response object. The default ActionController::Base - # implementation includes RackConvenience, which makes a request + # implementation includes RackDelegation, which makes a request # and response object available. You might wish to control the # environment and response manually for performance reasons. @@ -57,8 +57,8 @@ module ActionController end # Basic implementations for content_type=, location=, and headers are - # provided to reduce the dependency on the RackConvenience module - # in Rendering and Redirecting. + # provided to reduce the dependency on the RackDelegation module + # in Renderer and Redirector. def content_type=(type) headers["Content-Type"] = type.to_s diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb index 5156fbc1d5..61e7ece90d 100644 --- a/actionpack/lib/action_controller/metal/conditional_get.rb +++ b/actionpack/lib/action_controller/metal/conditional_get.rb @@ -2,7 +2,7 @@ module ActionController module ConditionalGet extend ActiveSupport::Concern - include RackConvenience + include RackDelegation include Head # Sets the etag, last_modified, or both on the response and renders a diff --git a/actionpack/lib/action_controller/metal/cookies.rb b/actionpack/lib/action_controller/metal/cookies.rb index 6855ca1478..e27374e4c4 100644 --- a/actionpack/lib/action_controller/metal/cookies.rb +++ b/actionpack/lib/action_controller/metal/cookies.rb @@ -46,7 +46,7 @@ module ActionController #:nodoc: module Cookies extend ActiveSupport::Concern - include RackConvenience + include RackDelegation included do helper_method :cookies diff --git a/actionpack/lib/action_controller/metal/rack_convenience.rb b/actionpack/lib/action_controller/metal/rack_convenience.rb deleted file mode 100644 index f0837c10e8..0000000000 --- a/actionpack/lib/action_controller/metal/rack_convenience.rb +++ /dev/null @@ -1,28 +0,0 @@ -module ActionController - module RackConvenience - extend ActiveSupport::Concern - - included do - delegate :session, :reset_session, :to => "@_request" - delegate :headers, :status=, :location=, :content_type=, - :status, :location, :content_type, :to => "@_response" - attr_internal :request - end - - def dispatch(action, env) - @_request = ActionDispatch::Request.new(env) - @_response = ActionDispatch::Response.new - @_response.request = request - super - end - - def params - @_params ||= @_request.parameters - end - - def response_body=(body) - response.body = body if response - super - end - end -end diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb new file mode 100644 index 0000000000..5141918499 --- /dev/null +++ b/actionpack/lib/action_controller/metal/rack_delegation.rb @@ -0,0 +1,28 @@ +module ActionController + module RackDelegation + extend ActiveSupport::Concern + + included do + delegate :session, :reset_session, :to => "@_request" + delegate :headers, :status=, :location=, :content_type=, + :status, :location, :content_type, :to => "@_response" + attr_internal :request + end + + def dispatch(action, env) + @_request = ActionDispatch::Request.new(env) + @_response = ActionDispatch::Response.new + @_response.request = request + super + end + + def params + @_params ||= @_request.parameters + end + + def response_body=(body) + response.body = body if response + super + end + end +end diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index a4a1116d9e..c193a5eff4 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -2,7 +2,7 @@ module ActionController module Testing extend ActiveSupport::Concern - include RackConvenience + include RackDelegation # OMG MEGA HAX def process_with_new_base_test(request, response) diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 14c6523045..8c3810ebcb 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -2,7 +2,7 @@ module ActionController module UrlFor extend ActiveSupport::Concern - include RackConvenience + include 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: -- cgit v1.2.3 From 36c13cc07a45cbfa5d06c89001a092c70b07e253 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 20 Dec 2009 18:15:20 -0800 Subject: Rename RenderOptions to Renderers --- actionpack/lib/action_controller/base.rb | 2 +- .../lib/action_controller/metal/render_options.rb | 92 ---------------------- .../lib/action_controller/metal/renderers.rb | 91 +++++++++++++++++++++ 3 files changed, 92 insertions(+), 93 deletions(-) delete mode 100644 actionpack/lib/action_controller/metal/render_options.rb create mode 100644 actionpack/lib/action_controller/metal/renderers.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ec64cc1a39..d84705434d 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -10,7 +10,7 @@ module ActionController include ActionController::UrlFor include ActionController::Redirecting include ActionController::Rendering - include ActionController::RenderOptions::All + include ActionController::Renderers::All include ActionController::Layouts include ActionController::ConditionalGet include ActionController::RackConvenience diff --git a/actionpack/lib/action_controller/metal/render_options.rb b/actionpack/lib/action_controller/metal/render_options.rb deleted file mode 100644 index b6a7ca0eda..0000000000 --- a/actionpack/lib/action_controller/metal/render_options.rb +++ /dev/null @@ -1,92 +0,0 @@ -module ActionController - - def self.add_renderer(key, &block) - RenderOptions.add(key, &block) - end - - module RenderOptions - extend ActiveSupport::Concern - - included do - extlib_inheritable_accessor :_renderers - self._renderers = {} - end - - module ClassMethods - def _write_render_options - renderers = _renderers.map do |name, value| - <<-RUBY_EVAL - if options.key?(:#{name}) - _process_options(options) - return _render_option_#{name}(options[:#{name}], options) - end - RUBY_EVAL - end - - class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 - def _handle_render_options(options) - #{renderers.join} - end - RUBY_EVAL - end - - def use_renderers(*args) - args.each do |key| - _renderers[key] = RENDERERS[key] - end - _write_render_options - end - alias use_renderer use_renderers - end - - def render_to_body(options) - _handle_render_options(options) || super - end - - RENDERERS = {} - def self.add(key, &block) - define_method("_render_option_#{key}", &block) - RENDERERS[key] = block - All._write_render_options - end - - module All - extend ActiveSupport::Concern - include RenderOptions - - INCLUDED = [] - included do - self._renderers = RENDERERS - _write_render_options - INCLUDED << self - end - - def self._write_render_options - INCLUDED.each(&:_write_render_options) - end - end - - add :json do |json, options| - json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str) - json = "#{options[:callback]}(#{json})" unless options[:callback].blank? - self.content_type ||= Mime::JSON - self.response_body = json - end - - add :js do |js, options| - self.content_type ||= Mime::JS - self.response_body = js.respond_to?(:to_js) ? js.to_js : js - end - - add :xml do |xml, options| - self.content_type ||= Mime::XML - self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml - end - - add :update do |proc, options| - generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc) - self.content_type = Mime::JS - self.response_body = generator.to_s - end - end -end diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb new file mode 100644 index 0000000000..c1ba47927a --- /dev/null +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -0,0 +1,91 @@ +module ActionController + def self.add_renderer(key, &block) + Renderers.add(key, &block) + end + + module Renderers + extend ActiveSupport::Concern + + included do + extlib_inheritable_accessor :_renderers + self._renderers = {} + end + + module ClassMethods + def _write_render_options + renderers = _renderers.map do |name, value| + <<-RUBY_EVAL + if options.key?(:#{name}) + _process_options(options) + return _render_option_#{name}(options[:#{name}], options) + end + RUBY_EVAL + end + + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def _handle_render_options(options) + #{renderers.join} + end + RUBY_EVAL + end + + def use_renderers(*args) + args.each do |key| + _renderers[key] = RENDERERS[key] + end + _write_render_options + end + alias use_renderer use_renderers + end + + def render_to_body(options) + _handle_render_options(options) || super + end + + RENDERERS = {} + def self.add(key, &block) + define_method("_render_option_#{key}", &block) + RENDERERS[key] = block + All._write_render_options + end + + module All + extend ActiveSupport::Concern + include Renderers + + INCLUDED = [] + included do + self._renderers = RENDERERS + _write_render_options + INCLUDED << self + end + + def self._write_render_options + INCLUDED.each(&:_write_render_options) + end + end + + add :json do |json, options| + json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str) + json = "#{options[:callback]}(#{json})" unless options[:callback].blank? + self.content_type ||= Mime::JSON + self.response_body = json + end + + add :js do |js, options| + self.content_type ||= Mime::JS + self.response_body = js.respond_to?(:to_js) ? js.to_js : js + end + + add :xml do |xml, options| + self.content_type ||= Mime::XML + self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml + end + + add :update do |proc, options| + generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc) + self.content_type = Mime::JS + self.response_body = generator.to_s + end + end +end -- cgit v1.2.3 From 17f66473bce0decb2e5ff23142d4046056ccca1b Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sun, 20 Dec 2009 18:50:47 -0800 Subject: AC::Head now doesn't have an unfulfilled Rendering dependency, and instead works just fine standalone (which means that ConditionalGet also doesn't have a Rendering dependency) --- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/metal.rb | 5 +++++ actionpack/lib/action_controller/metal/head.rb | 7 ++++++- actionpack/lib/action_controller/metal/redirecting.rb | 12 ++---------- 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index e6cde7fd35..452f0cd4f0 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -89,7 +89,7 @@ module ActionController end if options[:status] - options[:status] = _interpret_status(options[:status]) + options[:status] = ActionDispatch::StatusCodes[options[:status]] end options[:update] = blk if block_given? diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 8433be2320..93a19f8f93 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -68,6 +68,10 @@ module ActionController headers["Location"] = url end + def status=(status) + @_status = ActionDispatch::StatusCodes[status] + end + # :api: private def dispatch(name, env) @_env = env @@ -92,6 +96,7 @@ module ActionController def initialize(controller, action) @controller, @action = controller, action + @_formats = [Mime::HTML] end def call(env) diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb index 68fa0a0402..c82d9cf369 100644 --- a/actionpack/lib/action_controller/metal/head.rb +++ b/actionpack/lib/action_controller/metal/head.rb @@ -1,5 +1,7 @@ module ActionController module Head + include UrlFor + # Return a response that has no content (merely headers). The options # argument is interpreted to be a hash of header names and values. # This allows you to easily return a response that consists only of @@ -21,7 +23,10 @@ module ActionController headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s end - render :nothing => true, :status => status, :location => location + self.status = status + self.location = url_for(location) if location + self.content_type = Mime[formats.first] + self.response_body = " " end end end \ No newline at end of file diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index d101f920e3..39dc23024c 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -62,9 +62,9 @@ module ActionController private def _extract_redirect_to_status(options, response_status) status = if options.is_a?(Hash) && options.key?(:status) - _interpret_status(options.delete(:status)) + ActionDispatch::StatusCodes[options.delete(:status)] elsif response_status.key?(:status) - _interpret_status(response_status[:status]) + ActionDispatch::StatusCodes[response_status[:status]] else 302 end @@ -86,13 +86,5 @@ module ActionController url_for(options) end.gsub(/[\r\n]/, '') end - - def _interpret_status(status) - if status.is_a?(Symbol) - (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500) - else - status.to_i - end - end end end -- cgit v1.2.3 From f82e1046f893c80c6234495f1bca28b4fb6520c9 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 21 Dec 2009 17:29:59 -0600 Subject: reset_session needs to be a real method so flash can override it --- actionpack/lib/action_controller/metal/rack_delegation.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb index 5141918499..833475cff7 100644 --- a/actionpack/lib/action_controller/metal/rack_delegation.rb +++ b/actionpack/lib/action_controller/metal/rack_delegation.rb @@ -3,7 +3,7 @@ module ActionController extend ActiveSupport::Concern included do - delegate :session, :reset_session, :to => "@_request" + delegate :session, :to => "@_request" delegate :headers, :status=, :location=, :content_type=, :status, :location, :content_type, :to => "@_response" attr_internal :request @@ -24,5 +24,9 @@ module ActionController response.body = body if response super end + + def reset_session + @_request.reset_session + end end end -- cgit v1.2.3 From 4964d3b02cd5c87d821ab7d41d243154c727185d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 22 Dec 2009 20:17:27 +0100 Subject: Make ActionMailer::Base inherit from AbstractController::Base Signed-off-by: Yehuda Katz --- actionpack/lib/action_controller/base.rb | 1 + actionpack/lib/action_controller/metal/logger.rb | 34 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 actionpack/lib/action_controller/metal/logger.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 452f0cd4f0..f75b6ed641 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -14,6 +14,7 @@ module ActionController include ActionController::Layouts include ActionController::ConditionalGet include ActionController::RackDelegation + include ActionController::Logger include ActionController::Benchmarking include ActionController::Configuration diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb new file mode 100644 index 0000000000..956d7dd371 --- /dev/null +++ b/actionpack/lib/action_controller/metal/logger.rb @@ -0,0 +1,34 @@ +require 'abstract_controller/logger' + +module ActionController + module Logger + # Override process_action in the AbstractController::Base + # to log details about the method. + def process_action(action) + result = ActiveSupport::Notifications.instrument(:process_action, + :controller => self, :action => action) do + super + end + + if logger + log = AbstractController::Logger::DelayedLog.new do + "\n\nProcessing #{self.class.name}\##{action_name} " \ + "to #{request.formats} (for #{request_origin}) " \ + "[#{request.method.to_s.upcase}]" + end + + logger.info(log) + end + + result + end + + private + + # Returns the request origin with the IP and time. This needs to be cached, + # otherwise we would get different results for each time it calls. + def request_origin + @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}" + end + end +end -- cgit v1.2.3 From a1bf2f96ce6f086de8519e344ee7e396ae3da9bb Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 22 Dec 2009 16:08:03 -0600 Subject: AD::StatusCodes support is now part of rack --- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/metal.rb | 2 +- actionpack/lib/action_controller/metal/redirecting.rb | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index f75b6ed641..dbba69f637 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -90,7 +90,7 @@ module ActionController end if options[:status] - options[:status] = ActionDispatch::StatusCodes[options[:status]] + options[:status] = Rack::Utils.status_code(options[:status]) end options[:update] = blk if block_given? diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 93a19f8f93..b436de9878 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -69,7 +69,7 @@ module ActionController end def status=(status) - @_status = ActionDispatch::StatusCodes[status] + @_status = Rack::Utils.status_code(status) end # :api: private diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index 39dc23024c..7a2f9a6fc5 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -58,18 +58,18 @@ module ActionController logger.info("Redirected to #{location}") if logger && logger.info? end - + private def _extract_redirect_to_status(options, response_status) status = if options.is_a?(Hash) && options.key?(:status) - ActionDispatch::StatusCodes[options.delete(:status)] + Rack::Utils.status_code(options.delete(:status)) elsif response_status.key?(:status) - ActionDispatch::StatusCodes[response_status[:status]] + Rack::Utils.status_code(response_status[:status]) else 302 end end - + def _compute_redirect_to_location(options) case options # The scheme name consist of a letter followed by any combination of -- cgit v1.2.3 From 2d0c703c922758dc36df8a20a56894484013b0f1 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 22 Dec 2009 16:18:22 -0600 Subject: Use Rack::Runtime middleware so the reported time includes the entire middleware stack --- actionpack/lib/action_controller/metal/benchmarking.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/metal/benchmarking.rb b/actionpack/lib/action_controller/metal/benchmarking.rb index e58df69172..f73f635b0d 100644 --- a/actionpack/lib/action_controller/metal/benchmarking.rb +++ b/actionpack/lib/action_controller/metal/benchmarking.rb @@ -53,7 +53,6 @@ module ActionController #:nodoc: log_message << " [#{complete_request_uri rescue "unknown"}]" logger.info(log_message) - response.headers["X-Runtime"] = "%.0f" % ms else super end -- cgit v1.2.3 From b1aee9f4eebdae4fad38572359649c097c731b77 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 22 Dec 2009 17:11:21 -0600 Subject: All AD modules are "deferrable" --- actionpack/lib/action_controller/metal/rack_delegation.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb index 833475cff7..bb55383631 100644 --- a/actionpack/lib/action_controller/metal/rack_delegation.rb +++ b/actionpack/lib/action_controller/metal/rack_delegation.rb @@ -1,3 +1,6 @@ +require 'action_dispatch/http/request' +require 'action_dispatch/http/response' + module ActionController module RackDelegation extend ActiveSupport::Concern -- cgit v1.2.3 From ace20bd25e3818b7f29c222643dd445c48b36425 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 22 Dec 2009 17:27:37 -0600 Subject: Flip deferrable autoload convention --- actionpack/lib/action_controller/caching.rb | 12 +++++----- .../lib/action_controller/vendor/html-scanner.rb | 26 ++++++++++++---------- 2 files changed, 21 insertions(+), 17 deletions(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index ad357cceda..d784138ebe 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -32,11 +32,13 @@ module ActionController #:nodoc: extend ActiveSupport::Concern extend ActiveSupport::Autoload - autoload :Actions - autoload :Fragments - autoload :Pages - autoload :Sweeper, 'action_controller/caching/sweeping' - autoload :Sweeping, 'action_controller/caching/sweeping' + eager_autoload do + autoload :Actions + autoload :Fragments + autoload :Pages + autoload :Sweeper, 'action_controller/caching/sweeping' + autoload :Sweeping, 'action_controller/caching/sweeping' + end included do @@cache_store = nil diff --git a/actionpack/lib/action_controller/vendor/html-scanner.rb b/actionpack/lib/action_controller/vendor/html-scanner.rb index 2cb20ddd05..879b31e60e 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner.rb @@ -3,16 +3,18 @@ $LOAD_PATH << "#{File.dirname(__FILE__)}/html-scanner" module HTML extend ActiveSupport::Autoload - autoload :CDATA, 'html/node' - autoload :Document, 'html/document' - autoload :FullSanitizer, 'html/sanitizer' - autoload :LinkSanitizer, 'html/sanitizer' - autoload :Node, 'html/node' - autoload :Sanitizer, 'html/sanitizer' - autoload :Selector, 'html/selector' - autoload :Tag, 'html/node' - autoload :Text, 'html/node' - autoload :Tokenizer, 'html/tokenizer' - autoload :Version, 'html/version' - autoload :WhiteListSanitizer, 'html/sanitizer' + eager_autoload do + autoload :CDATA, 'html/node' + autoload :Document, 'html/document' + autoload :FullSanitizer, 'html/sanitizer' + autoload :LinkSanitizer, 'html/sanitizer' + autoload :Node, 'html/node' + autoload :Sanitizer, 'html/sanitizer' + autoload :Selector, 'html/selector' + autoload :Tag, 'html/node' + autoload :Text, 'html/node' + autoload :Tokenizer, 'html/tokenizer' + autoload :Version, 'html/version' + autoload :WhiteListSanitizer, 'html/sanitizer' + end end -- cgit v1.2.3 From 38aeb1528c376f7a058beea6db0a328720b85f01 Mon Sep 17 00:00:00 2001 From: Carlhuda Date: Wed, 23 Dec 2009 14:55:12 -0800 Subject: Moving out some framework specific initializers into the framework libraries. --- actionpack/lib/action_controller/rails.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 actionpack/lib/action_controller/rails.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/rails.rb b/actionpack/lib/action_controller/rails.rb new file mode 100644 index 0000000000..c2d753f9ef --- /dev/null +++ b/actionpack/lib/action_controller/rails.rb @@ -0,0 +1,27 @@ +module ActionController + class Plugin < Rails::Plugin + plugin_name :action_controller + + initializer "action_controller.set_configs" do |app| + app.config.action_controller.each do |k,v| + ActionController::Base.send "#{k}=", v + end + end + + # TODO: ActionController::Base.logger should delegate to its own config.logger + initializer "action_controller.logger" do + ActionController::Base.logger ||= Rails.logger + end + + # Routing must be initialized after plugins to allow the former to extend the routes + # --- + # If Action Controller is not one of the loaded frameworks (Configuration#frameworks) + # this does nothing. Otherwise, it loads the routing definitions and sets up + # loading module used to lazily load controllers (Configuration#controller_paths). + initializer "action_controller.initialize_routing" do |app| + app.route_configuration_files << app.config.routes_configuration_file + app.route_configuration_files << app.config.builtin_routes_configuration_file + app.reload_routes! + end + end +end \ No newline at end of file -- cgit v1.2.3 From d2bd71a145ddc5e3e3750edc9a09eab742aaf02a Mon Sep 17 00:00:00 2001 From: Carlhuda Date: Wed, 23 Dec 2009 17:01:07 -0800 Subject: Finish moving config.frameworks-dependent code to the framework plugin --- actionpack/lib/action_controller/notifications.rb | 10 --- actionpack/lib/action_controller/rails.rb | 75 +++++++++++++++++++++++ 2 files changed, 75 insertions(+), 10 deletions(-) delete mode 100644 actionpack/lib/action_controller/notifications.rb (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/notifications.rb b/actionpack/lib/action_controller/notifications.rb deleted file mode 100644 index 1a4f29e0e2..0000000000 --- a/actionpack/lib/action_controller/notifications.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'active_support/notifications' - -ActiveSupport::Notifications.subscribe(/(read|write|cache|expire|exist)_(fragment|page)\??/) do |*args| - event = ActiveSupport::Notifications::Event.new(*args) - - if logger = ActionController::Base.logger - human_name = event.name.to_s.humanize - logger.info("#{human_name} (%.1fms)" % event.duration) - end -end diff --git a/actionpack/lib/action_controller/rails.rb b/actionpack/lib/action_controller/rails.rb index c2d753f9ef..36a52b3149 100644 --- a/actionpack/lib/action_controller/rails.rb +++ b/actionpack/lib/action_controller/rails.rb @@ -23,5 +23,80 @@ module ActionController app.route_configuration_files << app.config.builtin_routes_configuration_file app.reload_routes! end + + # Include middleware to serve up static assets + initializer "action_controller.initialize_static_server" do |app| + if app.config.serve_static_assets + app.config.middleware.use(ActionDispatch::Static, Rails.public_path) + end + end + + initializer "action_controller.initialize_middleware_stack" do |app| + middleware = app.config.middleware + middleware.use(::Rack::Lock, :if => lambda { ActionController::Base.allow_concurrency }) + middleware.use(::Rack::Runtime) + middleware.use(ActionDispatch::ShowExceptions, lambda { ActionController::Base.consider_all_requests_local }) + middleware.use(ActionDispatch::Callbacks, lambda { ActionController::Dispatcher.prepare_each_request }) + middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options }) + middleware.use(ActionDispatch::ParamsParser) + middleware.use(::Rack::MethodOverride) + middleware.use(::Rack::Head) + middleware.use(ActionDispatch::StringCoercion) + end + + initializer "action_controller.initialize_framework_caches" do + ActionController::Base.cache_store ||= RAILS_CACHE + end + + # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+ + # (but only for those frameworks that are to be loaded). If the framework's + # paths have already been set, it is not changed, otherwise it is + # set to use Configuration#view_path. + initializer "action_controller.initialize_framework_views" do |app| + # TODO: this should be combined with the logic for default config.action_controller.view_paths + view_path = ActionView::PathSet.type_cast(app.config.view_path, app.config.cache_classes) + ActionController::Base.view_paths = view_path if ActionController::Base.view_paths.blank? + end + + initializer "action_controller.initialize_metal" do |app| + Rails::Rack::Metal.requested_metals = app.config.metals + + app.config.middleware.insert_before(:"ActionDispatch::ParamsParser", + Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?) + end + + # # Prepare dispatcher callbacks and run 'prepare' callbacks + initializer "action_controller.prepare_dispatcher" do |app| + # TODO: This used to say unless defined?(Dispatcher). Find out why and fix. + require 'rails/dispatcher' + + Dispatcher.define_dispatcher_callbacks(app.config.cache_classes) + + unless app.config.cache_classes + # Setup dev mode route reloading + routes_last_modified = app.routes_changed_at + reload_routes = lambda do + unless app.routes_changed_at == routes_last_modified + routes_last_modified = app.routes_changed_at + app.reload_routes! + end + end + ActionDispatch::Callbacks.before_dispatch { |callbacks| reload_routes.call } + end + end + + initializer "action_controller.notifications" do |app| + require 'active_support/notifications' + + ActiveSupport::Notifications.subscribe(/(read|write|cache|expire|exist)_(fragment|page)\??/) do |*args| + event = ActiveSupport::Notifications::Event.new(*args) + + if logger = ActionController::Base.logger + human_name = event.name.to_s.humanize + logger.info("#{human_name} (%.1fms)" % event.duration) + end + end + end + end end \ No newline at end of file -- cgit v1.2.3