diff options
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/CHANGELOG | 17 | ||||
-rw-r--r-- | actionpack/lib/action_controller/flash.rb | 154 | ||||
-rw-r--r-- | actionpack/lib/action_controller/test_process.rb | 4 | ||||
-rw-r--r-- | actionpack/test/controller/action_pack_assertions_test.rb | 3 | ||||
-rw-r--r-- | actionpack/test/controller/flash_test.rb | 35 |
5 files changed, 175 insertions, 38 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index dcaa5cecd4..96895a9529 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,22 @@ *SVN* +* 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]. Example of flash.now: + + class SomethingController < ApplicationController + def save + ... + if @something.save + # will redirect, use flash + flash['message'] = 'Save successful' + redirect_to :action => 'list' + else + # no redirect, message is for current action, use flash.now + flash.now['message'] = 'Save failed, review' + render_action 'edit' + end + end + end + * Added to_param call for parameters when composing an url using url_for from something else than strings #812 [Sam Stephenson]. Example: class Page 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 diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 48d7ed2f3f..4eadbf4e34 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -179,7 +179,6 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase # test the flash-based assertions with no flash at all def test_flash_assertions_negative process :nothing - assert_flash_not_exists assert_flash_empty assert_flash_has_no 'hello' assert_flash_has_no 'qwerty' @@ -230,7 +229,7 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase # check the empty flashing def test_flash_me_naked process :flash_me_naked - assert @response.has_flash? + assert !@response.has_flash? assert !@response.has_flash_with_contents? end diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index 033477fe39..3a6e828bc8 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -7,12 +7,26 @@ class FlashTest < Test::Unit::TestCase render_text "hello" end + def set_flash_now + flash.now["that"] = "hello" + @flash_copy = {}.update flash + render_text "hello" + end + + def attempt_to_use_flash_now + @flash_copy = {}.update flash + @flashy = flash["that"] + render_text "hello" + end + def use_flash + @flash_copy = {}.update flash @flashy = flash["that"] render_text "hello" end def use_flash_and_keep_it + @flash_copy = {}.update flash @flashy = flash["that"] keep_flash render_text "hello" @@ -33,11 +47,11 @@ class FlashTest < Test::Unit::TestCase @request.action = "use_flash" first_response = process_request - assert_equal "hello", first_response.template.assigns["flash"]["that"] + assert_equal "hello", first_response.template.assigns["flash_copy"]["that"] assert_equal "hello", first_response.template.assigns["flashy"] second_response = process_request - assert_nil second_response.template.assigns["flash"]["that"], "On second flash" + assert_nil second_response.template.assigns["flash_copy"]["that"], "On second flash" end def test_keep_flash @@ -46,17 +60,28 @@ class FlashTest < Test::Unit::TestCase @request.action = "use_flash_and_keep_it" first_response = process_request - assert_equal "hello", first_response.template.assigns["flash"]["that"] + assert_equal "hello", first_response.template.assigns["flash_copy"]["that"] assert_equal "hello", first_response.template.assigns["flashy"] @request.action = "use_flash" second_response = process_request - assert_equal "hello", second_response.template.assigns["flash"]["that"], "On second flash" + assert_equal "hello", second_response.template.assigns["flash_copy"]["that"], "On second flash" third_response = process_request - assert_nil third_response.template.assigns["flash"]["that"], "On third flash" + assert_nil third_response.template.assigns["flash_copy"]["that"], "On third flash" end + def test_flash_now + @request.action = "set_flash_now" + response = process_request + assert_equal "hello", response.template.assigns["flash_copy"]["that"] + + @request.action = "attempt_to_use_flash_now" + first_response = process_request + assert_nil first_response.template.assigns["flash_copy"]["that"] + assert_nil first_response.template.assigns["flashy"] + end + private def initialize_request_and_response @request = ActionController::TestRequest.new |