aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/flash.rb154
-rw-r--r--actionpack/lib/action_controller/test_process.rb4
2 files changed, 127 insertions, 31 deletions
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 <tt>flash["notice"]</tt> to read a notice you put there or
- # <tt>flash["notice"] = "hello"</tt> 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 (<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.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 <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)
+ 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 <tt>flash["notice"]</tt> to read a notice you put there or
+ # <tt>flash["notice"] = "hello"</tt> to put a new one.
+ def flash #:doc:
+ @session['flash'] ||= FlashHash.new
+ end
+
+ # deprecated. use <tt>flash.keep</tt> 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
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb
index e3ab045a12..3d9a335eff 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/test_process.rb
@@ -168,7 +168,7 @@ module ActionController #:nodoc:
# do we have a flash?
def has_flash?
- !session['flash'].nil?
+ !session['flash'].empty?
end
# do we have a flash that has contents?
@@ -283,4 +283,4 @@ module Test
end
end
end
-end \ No newline at end of file
+end