aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2010-01-15 14:44:27 -0600
committerJoshua Peek <josh@joshpeek.com>2010-01-15 14:55:13 -0600
commitead93c5be5b0f1945b7d0302f1aae4685ee3f2fb (patch)
treea6213e17ef6d01215b606b5fd11dcd05ca0dafda /actionpack/lib/action_dispatch
parent3da29f647bad5e79c90721ac23658940abddd27c (diff)
downloadrails-ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb.tar.gz
rails-ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb.tar.bz2
rails-ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb.zip
Move Flash into middleware
Diffstat (limited to 'actionpack/lib/action_dispatch')
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb174
2 files changed, 174 insertions, 4 deletions
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 3d0aab8a06..22a08ec10d 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -463,10 +463,6 @@ EOM
@env['rack.session.options'] = options
end
- def flash
- session['flash'] || {}
- end
-
# Returns the authorization header regardless of whether it was specified directly or through one of the
# proxy alternatives.
def authorization
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 <tt>flash["notice"]</tt> to
+ # read a notice you put there or <tt>flash["notice"] = "hello"</tt>
+ # 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 <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 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] %>
+ # <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.
+ 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 (<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
+
+ # 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 <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
+
+ 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