HTTP是無狀態的通訊協定,對伺服器來說,每次都是新請求,為了要讓伺服器得知上次請求與此次請求的關係,有一些會話管理機制,像是先前介紹過的 隱藏欄位、Cookie 或高階的 session 機制。
Rails提供的flash方法,也是一種高階的會話機制,其作用週期僅止於兩次請求之間。如果在此次請求時如下設置:
flash[:notice] = "Post successfullly created"
再次瀏覽請求時,可以如下取得訊息(假設是在樣版檔案中):
<%= flash[:notice] %>
這次請求結束後,flash[:notice]設置的訊息就清除了,第三次請求時若嘗試flash[:notice]就不會再取得任何訊息。經常應用的場合是在redirect_to前後,在要求重新導向前使用flash設置訊息,瀏覽器被重新導向後利用flash取得訊息。
實際上,flash方法會嘗試使用session方法指定"flash"取得ActionDispatch::Flash::FlashHash實例,如果沒有就建立新的ActionDispatch::Flash::FlashHash實例:
# File actionpack/lib/action_dispatch/middleware/flash.rb, line 6
def flash
@env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new)
end
所以flash底層是利用session機制來處理,上次請求設定訊息用的ActionDispatch::Flash::FlashHash實例,其實會使用session設定名稱為"flash"加以儲存,下次請求結束後,session中設定的ActionDispatch::Flash::FlashHash實例就會被清除,因此取名為flash,代表的就是訊息在兩個請求間一閃而過。
由於使用flash設定與取得:notice、:alert是常見需求,因此ActionDispatch::Flash::FlashHash也提供notice與alert方法。例如:
flash.notice = "Post successfully created" # 可於下次請求使用flash.notice取得訊息
flash.alert = "Post failed" # 可於下次請求使用flash.alert取得訊息
實際上原始碼是:
# File actionpack/lib/action_dispatch/middleware/flash.rb, line 200
def alert
self[:alert]
end
# File actionpack/lib/action_dispatch/middleware/flash.rb, line 205
def alert=(message)
self[:alert] = message
end
# File actionpack/lib/action_dispatch/middleware/flash.rb, line 210
def notice
self[:notice]
end
# File actionpack/lib/action_dispatch/middleware/flash.rb, line 215
def notice=(message)
self[:notice] = message
end
有時候,你只想讓flash設定的訊息,只在此次請求有用。例如:
def do_some
....
if some_cond?
flash.alert = "something must be wrong"
redirect_to "/test/error"
end
end
def do_other
...
if some_cond?
flash.alert = "shit happens"
render "/test/error"
end
end
也這"test/error"的樣版是會共用的錯誤處理樣版,都是這麼寫:
<%= flash.alert %>
在do_some時會要求重新導向,但是在do_other時你想直接呈現,然而以上的寫法,do_other結束後,重新請求還是可以取得上次flash.alert的訊息。你應該使用flash.now。例如:
def do_other
...
if some_cond?
flash.now.alert = "shit happens"
render "/test/error"
end
end
flash.now會使用ActionDispatch::Flash::FlashNow將原有的ActionDispatch::Flash::FlashHash實例包裹後傳回:
# File actionpack/lib/action_dispatch/middleware/flash.rb, line 158
def now
@now ||= FlashNow.new(self)
end
ActionDispatch::Flash::FlashNow實例設定的訊息,會在此次請求之後清除,因此下次請求就取不到訊息了。
如果在下次請求使用過flash設定的訊息後,想要保有某些訊息至第三次請求,其它訊息棄用,則可以使用keep方法。例如第一次請求若為:
flash[:notice1] = "test1"
flash[:notice2] = "test2"
第二次請求時,若呼叫了:
flash.keep(:notice1)
則第二次請求結束後,:notice1被保留,:notice2被丟棄,因此第三次請求時,可以取得flash[:notice1]的值,但取不到flash[:notice2]的值。如果呼叫keep時沒有指定保留哪些訊息,則所有訊息保留至下一次請求。discard則是與keep作用相反的方法,被指定的訊息將被丟棄,其它訊息再保留至下一次請求。