From a35cf348bf918c7170ff4890d25d2d48a133edc1 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 20 Mar 2005 19:12:53 +0000 Subject: Added a much improved Flash module that allows for finer-grained control on expiration and allows you to flash the current action #839 [Caio Chassot] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@942 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/lib/action_controller/flash.rb | 154 ++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 29 deletions(-) (limited to 'actionpack/lib/action_controller/flash.rb') diff --git a/actionpack/lib/action_controller/flash.rb b/actionpack/lib/action_controller/flash.rb index b4e8d75bf6..e3a8a8c8c4 100644 --- a/actionpack/lib/action_controller/flash.rb +++ b/actionpack/lib/action_controller/flash.rb @@ -21,45 +21,141 @@ module ActionController #:nodoc: # # This example just places a string in the flash, but you can put any object in there. And of course, you can put as many # as you like at a time too. Just remember: They'll be gone by the time the next action has been performed. + # + # See docs on the FlashHash class for more details about the flash. module Flash + def self.append_features(base) #:nodoc: super base.before_filter(:fire_flash) - base.after_filter(:clear_flash) + base.after_filter(:sweep_flash) end - protected - # 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 #:doc: - if @session["flash"].nil? - @session["flash"] = {} - @session["flashes"] ||= 0 + class FlashNow #:nodoc: + def initialize flash + @flash = flash + end + + def []=(k, v) + @flash[k] = v + @flash.discard(k) + v + end + end + + class FlashHash < Hash + + def initialize #:nodoc: + super + @used = {} + end + + def []=(k, v) #:nodoc: + keep(k) + super + end + + def update h #:nodoc: + h.keys.each{|k| discard k } + super + end + + alias merge! update + + def replace h #:nodoc: + @used = {} + 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.keep # keep entire flash available for the next action + # flash.discard('warning') # discard the "warning" entry (it'll still be available for 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[k] + use(k) + else + delete(k) + @used.delete(k) + end end - @session["flash"] - end - - # Can be called by any action that would like to keep the current content of the flash around for one more action. - def keep_flash #:doc: - @session["flashes"] = 0 - end - - private - # Records that the contents of @session["flash"] was flashed to the action - def fire_flash - if @session["flash"] - @session["flashes"] += 1 unless @session["flash"].empty? - @assigns["flash"] = @session["flash"] + (@used.keys - keys).each{|k| @used.delete k } # clean up after keys that could have been left over by calling reject! or shift on the flash + 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) + def use(k=nil, v=true) + unless k.nil? + @used[k] = v else - @assigns["flash"] = {} + keys.each{|key| use key, v } end end - def clear_flash - if @session["flash"] && (@session["flashes"].nil? || @session["flashes"] >= 1) - @session["flash"] = {} - @session["flashes"] = 0 - end - end + end + + + protected + + # 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 #:doc: + @session['flash'] ||= FlashHash.new + end + + # deprecated. use flash.keep instead + def keep_flash #:doc: + flash.keep + end + + + private + + # marks flash entries as used and expose the flash to the view + def fire_flash + flash.discard + @assigns["flash"] = flash + end + + # deletes the flash entries that were not marked for keeping + def sweep_flash + flash.sweep + end + end end -- cgit v1.2.3