root/branches/1-2-stable/actionpack/lib/action_controller/flash.rb
| Revision 5021, 6.1 kB (checked in by david, 2 years ago) |
|---|
| Line | |
|---|---|
| 1 | module ActionController #:nodoc: |
| 2 | # The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed |
| 3 | # to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create action |
| 4 | # that sets <tt>flash[:notice] = "Successfully created"</tt> before redirecting to a display action that can then expose |
| 5 | # the flash to its template. Actually, that exposure is automatically done. Example: |
| 6 | # |
| 7 | # class WeblogController < ActionController::Base |
| 8 | # def create |
| 9 | # # save post |
| 10 | # flash[:notice] = "Successfully created post" |
| 11 | # redirect_to :action => "display", :params => { :id => post.id } |
| 12 | # end |
| 13 | # |
| 14 | # def display |
| 15 | # # doesn't need to assign the flash notice to the template, that's done automatically |
| 16 | # end |
| 17 | # end |
| 18 | # |
| 19 | # display.rhtml |
| 20 | # <% if flash[:notice] %><div class="notice"><%= flash[:notice] %></div><% end %> |
| 21 | # |
| 22 | # 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 |
| 23 | # as you like at a time too. Just remember: They'll be gone by the time the next action has been performed. |
| 24 | # |
| 25 | # See docs on the FlashHash class for more details about the flash. |
| 26 | module Flash |
| 27 | def self.included(base) |
| 28 | base.send :include, InstanceMethods |
| 29 | |
| 30 | base.class_eval do |
| 31 | alias_method_chain :assign_shortcuts, :flash |
| 32 | alias_method_chain :process_cleanup, :flash |
| 33 | alias_method_chain :reset_session, :flash |
| 34 | end |
| 35 | end |
| 36 | |
| 37 | |
| 38 | class FlashNow #:nodoc: |
| 39 | def initialize(flash) |
| 40 | @flash = flash |
| 41 | end |
| 42 | |
| 43 | def []=(k, v) |
| 44 | @flash[k] = v |
| 45 | @flash.discard(k) |
| 46 | v |
| 47 | end |
| 48 | |
| 49 | def [](k) |
| 50 | @flash[k] |
| 51 | end |
| 52 | end |
| 53 | |
| 54 | class FlashHash < Hash |
| 55 | def initialize #:nodoc: |
| 56 | super |
| 57 | @used = {} |
| 58 | end |
| 59 | |
| 60 | def []=(k, v) #:nodoc: |
| 61 | keep(k) |
| 62 | super |
| 63 | end |
| 64 | |
| 65 | def update(h) #:nodoc: |
| 66 | h.keys.each{ |k| discard(k) } |
| 67 | super |
| 68 | end |
| 69 | |
| 70 | alias :merge! :update |
| 71 | |
| 72 | def replace(h) #:nodoc: |
| 73 | @used = {} |
| 74 | super |
| 75 | end |
| 76 | |
| 77 | # Sets a flash that will not be available to the next action, only to the current. |
| 78 | # |
| 79 | # flash.now[:message] = "Hello current action" |
| 80 | # |
| 81 | # This method enables you to use the flash as a central messaging system in your app. |
| 82 | # When you need to pass an object to the next action, you use the standard flash assign (<tt>[]=</tt>). |
| 83 | # When you need to pass an object to the current action, you use <tt>now</tt>, and your object will |
| 84 | # vanish when the current action is done. |
| 85 | # |
| 86 | # Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>. |
| 87 | def now |
| 88 | FlashNow.new self |
| 89 | end |
| 90 | |
| 91 | # Keeps either the entire current flash or a specific flash entry available for the next action: |
| 92 | # |
| 93 | # flash.keep # keeps the entire flash |
| 94 | # flash.keep(:notice) # keeps only the "notice" entry, the rest of the flash is discarded |
| 95 | def keep(k = nil) |
| 96 | use(k, false) |
| 97 | end |
| 98 | |
| 99 | # Marks the entire flash or a single flash entry to be discarded by the end of the current action |
| 100 | # |
| 101 | # flash.keep # keep entire flash available for the next action |
| 102 | # flash.discard(:warning) # discard the "warning" entry (it'll still be available for the current action) |
| 103 | def discard(k = nil) |
| 104 | use(k) |
| 105 | end |
| 106 | |
| 107 | # Mark for removal entries that were kept, and delete unkept ones. |
| 108 | # |
| 109 | # This method is called automatically by filters, so you generally don't need to care about it. |
| 110 | def sweep #:nodoc: |
| 111 | keys.each do |k| |
| 112 | unless @used[k] |
| 113 | use(k) |
| 114 | else |
| 115 | delete(k) |
| 116 | @used.delete(k) |
| 117 | end |
| 118 | end |
| 119 | |
| 120 | (@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 |
| 121 | end |
| 122 | |
| 123 | private |
| 124 | # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods |
| 125 | # use() # marks the entire flash as used |
| 126 | # use('msg') # marks the "msg" entry as used |
| 127 | # use(nil, false) # marks the entire flash as unused (keeps it around for one more action) |
| 128 | # use('msg', false) # marks the "msg" entry as unused (keeps it around for one more action) |
| 129 | def use(k=nil, v=true) |
| 130 | unless k.nil? |
| 131 | @used[k] = v |
| 132 | else |
| 133 | keys.each{|key| use key, v } |
| 134 | end |
| 135 | end |
| 136 | end |
| 137 | |
| 138 | module InstanceMethods #:nodoc: |
| 139 | def assign_shortcuts_with_flash(request, response) #:nodoc: |
| 140 | assign_shortcuts_without_flash(request, response) |
| 141 | flash(:refresh) |
| 142 | end |
| 143 | |
| 144 | def process_cleanup_with_flash |
| 145 | flash.sweep if @_session |
| 146 | process_cleanup_without_flash |
| 147 | end |
| 148 | |
| 149 | def reset_session_with_flash |
| 150 | reset_session_without_flash |
| 151 | remove_instance_variable(:@_flash) |
| 152 | flash(:refresh) |
| 153 | end |
| 154 | |
| 155 | protected |
| 156 | # Access the contents of the flash. Use <tt>flash["notice"]</tt> to read a notice you put there or |
| 157 | # <tt>flash["notice"] = "hello"</tt> to put a new one. |
| 158 | # Note that if sessions are disabled only flash.now will work. |
| 159 | def flash(refresh = false) #:doc: |
| 160 | if !defined?(@_flash) || refresh |
| 161 | @_flash = |
| 162 | if session.is_a?(Hash) |
| 163 | # don't put flash in session if disabled |
| 164 | FlashHash.new |
| 165 | else |
| 166 | # otherwise, session is a CGI::Session or a TestSession |
| 167 | # so make sure it gets retrieved from/saved to session storage after request processing |
| 168 | session["flash"] ||= FlashHash.new |
| 169 | end |
| 170 | end |
| 171 | |
| 172 | @_flash |
| 173 | end |
| 174 | |
| 175 | # deprecated. use <tt>flash.keep</tt> instead |
| 176 | def keep_flash #:doc: |
| 177 | ActiveSupport::Deprecation.warn 'keep_flash is deprecated; use flash.keep instead.', caller |
| 178 | flash.keep |
| 179 | end |
| 180 | end |
| 181 | end |
| 182 | end |
Note: See TracBrowser for help on using the browser.