1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

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
This commit is contained in:
David Heinemeier Hansson 2005-03-20 19:12:53 +00:00
parent 800b86e4c7
commit a35cf348bf
5 changed files with 175 additions and 38 deletions

View file

@ -1,5 +1,22 @@
*SVN* *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: * Added to_param call for parameters when composing an url using url_for from something else than strings #812 [Sam Stephenson]. Example:
class Page class Page

View file

@ -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 # 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. # 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 module Flash
def self.append_features(base) #:nodoc: def self.append_features(base) #:nodoc:
super super
base.before_filter(:fire_flash) base.before_filter(:fire_flash)
base.after_filter(:clear_flash) base.after_filter(:sweep_flash)
end end
protected class FlashNow #:nodoc:
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to read a notice you put there or def initialize flash
# <tt>flash["notice"] = "hello"</tt> to put a new one. @flash = flash
def flash #:doc: end
if @session["flash"].nil?
@session["flash"] = {} def []=(k, v)
@session["flashes"] ||= 0 @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 end
@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 end
# Can be called by any action that would like to keep the current content of the flash around for one more action. private
def keep_flash #:doc:
@session["flashes"] = 0 # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods
end # use() # marks the entire flash as used
# use('msg') # marks the "msg" entry as used
private # use(nil, false) # marks the entire flash as unused (keeps it around for one more action)
# Records that the contents of @session["flash"] was flashed to the action # use('msg', false) # marks the "msg" entry as unused (keeps it around for one more action)
def fire_flash def use(k=nil, v=true)
if @session["flash"] unless k.nil?
@session["flashes"] += 1 unless @session["flash"].empty? @used[k] = v
@assigns["flash"] = @session["flash"]
else else
@assigns["flash"] = {} keys.each{|key| use key, v }
end end
end end
def clear_flash end
if @session["flash"] && (@session["flashes"].nil? || @session["flashes"] >= 1)
@session["flash"] = {}
@session["flashes"] = 0 protected
end
end # 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
end end

View file

@ -168,7 +168,7 @@ module ActionController #:nodoc:
# do we have a flash? # do we have a flash?
def has_flash? def has_flash?
!session['flash'].nil? !session['flash'].empty?
end end
# do we have a flash that has contents? # do we have a flash that has contents?
@ -283,4 +283,4 @@ module Test
end end
end end
end end
end end

View file

@ -179,7 +179,6 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
# test the flash-based assertions with no flash at all # test the flash-based assertions with no flash at all
def test_flash_assertions_negative def test_flash_assertions_negative
process :nothing process :nothing
assert_flash_not_exists
assert_flash_empty assert_flash_empty
assert_flash_has_no 'hello' assert_flash_has_no 'hello'
assert_flash_has_no 'qwerty' assert_flash_has_no 'qwerty'
@ -230,7 +229,7 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
# check the empty flashing # check the empty flashing
def test_flash_me_naked def test_flash_me_naked
process :flash_me_naked process :flash_me_naked
assert @response.has_flash? assert !@response.has_flash?
assert !@response.has_flash_with_contents? assert !@response.has_flash_with_contents?
end end

View file

@ -7,12 +7,26 @@ class FlashTest < Test::Unit::TestCase
render_text "hello" render_text "hello"
end 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 def use_flash
@flash_copy = {}.update flash
@flashy = flash["that"] @flashy = flash["that"]
render_text "hello" render_text "hello"
end end
def use_flash_and_keep_it def use_flash_and_keep_it
@flash_copy = {}.update flash
@flashy = flash["that"] @flashy = flash["that"]
keep_flash keep_flash
render_text "hello" render_text "hello"
@ -33,11 +47,11 @@ class FlashTest < Test::Unit::TestCase
@request.action = "use_flash" @request.action = "use_flash"
first_response = process_request 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"] assert_equal "hello", first_response.template.assigns["flashy"]
second_response = process_request 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 end
def test_keep_flash def test_keep_flash
@ -46,17 +60,28 @@ class FlashTest < Test::Unit::TestCase
@request.action = "use_flash_and_keep_it" @request.action = "use_flash_and_keep_it"
first_response = process_request 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"] assert_equal "hello", first_response.template.assigns["flashy"]
@request.action = "use_flash" @request.action = "use_flash"
second_response = process_request 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 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 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 private
def initialize_request_and_response def initialize_request_and_response
@request = ActionController::TestRequest.new @request = ActionController::TestRequest.new