From 53c6984944b03b5de036167a418593dfcd12e886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 3 Jan 2010 23:33:34 +0100 Subject: Add notifications to ActionDispatch::ShowExceptions, this can be used as hooks for plugins like ExceptionNotifier. --- .../action_dispatch/middleware/show_exceptions.rb | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 4ebc8a2ab9..af356707c6 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -1,7 +1,24 @@ require 'active_support/core_ext/exception' +require 'active_support/notifications' require 'action_dispatch/http/request' module ActionDispatch + # This middleware rescues any exception returned by the application and renders + # nice exception pages if it's being rescued locally. + # + # Every time an exception is caught, a notification is published, becoming a good API + # to deal with exceptions. So, if you want send an e-mail through ActionMailer + # everytime this notification is published, you just need to do the following: + # + # ActiveSupport::Notifications.subscribe "action_dispatch.show_exception" do |name, start, end, instrumentation_id, payload| + # ExceptionNotifier.deliver_exception(start, payload) + # end + # + # The payload is a hash which has to pairs: + # + # * :env - Contains the rack env for the given request; + # * :exception - The exception raised; + # class ShowExceptions LOCALHOST = '127.0.0.1'.freeze @@ -44,8 +61,11 @@ module ActionDispatch def call(env) @app.call(env) rescue Exception => exception - raise exception if env['action_dispatch.show_exceptions'] == false - render_exception(env, exception) + ActiveSupport::Notifications.instrument 'action_dispatch.show_exception', + :env => env, :exception => exception do + raise exception if env['action_dispatch.show_exceptions'] == false + render_exception(env, exception) + end end private -- cgit v1.2.3 From 562a00ba16746bf36b7d8b327fabae3dabfdb122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 4 Jan 2010 22:11:35 +0100 Subject: @_formats initialization should be AbstractController::Base. --- actionpack/lib/action_dispatch/middleware/show_exceptions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index af356707c6..10f04dcdf6 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -14,7 +14,7 @@ module ActionDispatch # ExceptionNotifier.deliver_exception(start, payload) # end # - # The payload is a hash which has to pairs: + # The payload is a hash which has two pairs: # # * :env - Contains the rack env for the given request; # * :exception - The exception raised; -- cgit v1.2.3 From 3f28e0bda6386ed25d07182dd39b84f6a7d330da Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 4 Jan 2010 19:46:21 -0600 Subject: Trash string coercion rack hacks --- .../action_dispatch/middleware/string_coercion.rb | 29 ---------------------- 1 file changed, 29 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/middleware/string_coercion.rb (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/string_coercion.rb b/actionpack/lib/action_dispatch/middleware/string_coercion.rb deleted file mode 100644 index 232e947835..0000000000 --- a/actionpack/lib/action_dispatch/middleware/string_coercion.rb +++ /dev/null @@ -1,29 +0,0 @@ -module ActionDispatch - class StringCoercion - class UglyBody < ActiveSupport::BasicObject - def initialize(body) - @body = body - end - - def each - @body.each do |part| - yield part.to_s - end - end - - private - def method_missing(*args, &block) - @body.__send__(*args, &block) - end - end - - def initialize(app) - @app = app - end - - def call(env) - status, headers, body = @app.call(env) - [status, headers, UglyBody.new(body)] - end - end -end -- cgit v1.2.3 From 8c8942ed4f2da52aa42ccd46560acb0b5fd37cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 14 Jan 2010 19:53:07 +0100 Subject: Move Dispatcher setup to Railties and add instrumentation hook. --- actionpack/lib/action_dispatch/middleware/callbacks.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb index 49bc20f11f..8098933e01 100644 --- a/actionpack/lib/action_dispatch/middleware/callbacks.rb +++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb @@ -1,4 +1,10 @@ module ActionDispatch + # Provide callbacks to be executed before and after the request dispatch. + # + # It also provides a to_prepare callback, which is performed in all requests + # in development by only once in production and notification callback for async + # operations. + # class Callbacks include ActiveSupport::Callbacks @@ -29,12 +35,6 @@ module ActionDispatch set_callback(:call, :after, *args, &block) end - class << self - # DEPRECATED - alias_method :before_dispatch, :before - alias_method :after_dispatch, :after - end - def initialize(app, prepare_each_request = false) @app, @prepare_each_request = app, prepare_each_request run_callbacks(:prepare) @@ -43,7 +43,10 @@ module ActionDispatch def call(env) run_callbacks(:call) do run_callbacks(:prepare) if @prepare_each_request - @app.call(env) + + ActiveSupport::Notifications.instrument "action_dispatch.callback" do + @app.call(env) + end end end end -- cgit v1.2.3 From 4598d8874948268e1162c1ef75d0bd565b1e0e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 15 Jan 2010 14:16:52 +0100 Subject: Ensure log is flushed and tailed on failures. --- actionpack/lib/action_dispatch/middleware/callbacks.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb index 8098933e01..5ec406e134 100644 --- a/actionpack/lib/action_dispatch/middleware/callbacks.rb +++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb @@ -43,11 +43,10 @@ module ActionDispatch def call(env) run_callbacks(:call) do run_callbacks(:prepare) if @prepare_each_request - - ActiveSupport::Notifications.instrument "action_dispatch.callback" do - @app.call(env) - end + @app.call(env) end + ensure + ActiveSupport::Notifications.instrument "action_dispatch.callback" end end end -- cgit v1.2.3 From 3eaf525213ccef5c63c9e296fa643ad416a3f84c Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 15 Jan 2010 12:35:18 -0600 Subject: Make HEAD method masquerade as GET so requests are routed correctly --- actionpack/lib/action_dispatch/middleware/head.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 actionpack/lib/action_dispatch/middleware/head.rb (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/head.rb b/actionpack/lib/action_dispatch/middleware/head.rb new file mode 100644 index 0000000000..56e2d2f2a8 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/head.rb @@ -0,0 +1,18 @@ +module ActionDispatch + class Head + def initialize(app) + @app = app + end + + def call(env) + if env["REQUEST_METHOD"] == "HEAD" + env["REQUEST_METHOD"] = "GET" + env["rack.methodoverride.original_method"] = "HEAD" + status, headers, body = @app.call(env) + [status, headers, []] + else + @app.call(env) + end + end + end +end -- cgit v1.2.3 From ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 15 Jan 2010 14:44:27 -0600 Subject: Move Flash into middleware --- actionpack/lib/action_dispatch/middleware/flash.rb | 174 +++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 actionpack/lib/action_dispatch/middleware/flash.rb (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb new file mode 100644 index 0000000000..99b36366d6 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -0,0 +1,174 @@ +module ActionDispatch + class Request + # Access the contents of the flash. Use flash["notice"] to + # read a notice you put there or flash["notice"] = "hello" + # to put a new one. + def flash + session['flash'] ||= Flash::FlashHash.new + end + end + + # 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 flash[:notice] = "Successfully created" 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 posts_path(@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] %> + #
<%= flash[:notice] %>
+ # <% 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. + class Flash + 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 ([]=). + # When you need to pass an object to the current action, you use now, and your object will + # vanish when the current action is done. + # + # Entries set via now are accessed the same way as standard entries: flash['my-key']. + 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 + + # Convenience accessor for flash[:alert] + def alert + self[:alert] + end + + # Convenience accessor for flash[:alert]= + def alert=(message) + self[:alert] = message + end + + # Convenience accessor for flash[:notice] + def notice + self[:notice] + end + + # Convenience accessor for flash[:notice]= + def notice=(message) + self[:notice] = message + end + + private + # Used internally by the keep and discard 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 + + def initialize(app) + @app = app + end + + def call(env) + if (session = env['rack.session']) && (flash = session['flash']) + flash.sweep + end + + @app.call(env) + ensure + if (session = env['rack.session']) && (flash = session['flash']) && flash.empty? + session.delete('flash') + end + end + end +end -- cgit v1.2.3 From 89082004b0381ec67b4a2782ef4d4f63853e586f Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 15 Jan 2010 16:20:12 -0600 Subject: Fix const reference for SessionRestoreError --- actionpack/lib/action_dispatch/middleware/session/abstract_store.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch/middleware') diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 7d4f0998ce..311880cabc 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -102,7 +102,7 @@ module ActionDispatch # Note that the regexp does not allow $1 to end with a ':' $1.constantize rescue LoadError, NameError => const_error - raise ActionDispatch::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n" + raise ActionDispatch::Session::SessionRestoreError, "Session contains objects whose class definition isn't available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: #{const_error.message} [#{const_error.class}])\n" end retry -- cgit v1.2.3