diff options
author | Joshua Peek <josh@joshpeek.com> | 2010-01-15 14:44:27 -0600 |
---|---|---|
committer | Joshua Peek <josh@joshpeek.com> | 2010-01-15 14:55:13 -0600 |
commit | ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb (patch) | |
tree | a6213e17ef6d01215b606b5fd11dcd05ca0dafda /actionpack/lib/action_dispatch/middleware | |
parent | 3da29f647bad5e79c90721ac23658940abddd27c (diff) | |
download | rails-ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb.tar.gz rails-ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb.tar.bz2 rails-ead93c5be5b0f1945b7d0302f1aae4685ee3f2fb.zip |
Move Flash into middleware
Diffstat (limited to 'actionpack/lib/action_dispatch/middleware')
-rw-r--r-- | actionpack/lib/action_dispatch/middleware/flash.rb | 174 |
1 files changed, 174 insertions, 0 deletions
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 |