~ubuntu-branches/ubuntu/raring/ruby-actionpack-3.2/raring

« back to all changes in this revision

Viewing changes to lib/action_dispatch/middleware/flash.rb

  • Committer: Package Import Robot
  • Author(s): Ondřej Surý
  • Date: 2012-04-25 09:14:01 UTC
  • Revision ID: package-import@ubuntu.com-20120425091401-3nkf83btcemhjquo
Tags: upstream-3.2.3
Import upstream version 3.2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
module ActionDispatch
 
2
  class Request
 
3
    # Access the contents of the flash. Use <tt>flash["notice"]</tt> to
 
4
    # read a notice you put there or <tt>flash["notice"] = "hello"</tt>
 
5
    # to put a new one.
 
6
    def flash
 
7
      @env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new)
 
8
    end
 
9
  end
 
10
 
 
11
  # The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed
 
12
  # to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
 
13
  # action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
 
14
  # then expose the flash to its template. Actually, that exposure is automatically done. Example:
 
15
  #
 
16
  #   class PostsController < ActionController::Base
 
17
  #     def create
 
18
  #       # save post
 
19
  #       flash[:notice] = "Post successfully created"
 
20
  #       redirect_to posts_path(@post)
 
21
  #     end
 
22
  #
 
23
  #     def show
 
24
  #       # doesn't need to assign the flash notice to the template, that's done automatically
 
25
  #     end
 
26
  #   end
 
27
  #
 
28
  #   show.html.erb
 
29
  #     <% if flash[:notice] %>
 
30
  #       <div class="notice"><%= flash[:notice] %></div>
 
31
  #     <% end %>
 
32
  #
 
33
  # Since the +notice+ and +alert+ keys are a common idiom, convenience accessors are available:
 
34
  #
 
35
  #   flash.alert = "You must be logged in"
 
36
  #   flash.notice = "Post successfully created"
 
37
  #
 
38
  # This example just places a string in the flash, but you can put any object in there. And of course, you can put as
 
39
  # many as you like at a time too. Just remember: They'll be gone by the time the next action has been performed.
 
40
  #
 
41
  # See docs on the FlashHash class for more details about the flash.
 
42
  class Flash
 
43
    KEY = 'action_dispatch.request.flash_hash'.freeze
 
44
 
 
45
    class FlashNow #:nodoc:
 
46
      attr_accessor :flash
 
47
 
 
48
      def initialize(flash)
 
49
        @flash = flash
 
50
      end
 
51
 
 
52
      def []=(k, v)
 
53
        @flash[k] = v
 
54
        @flash.discard(k)
 
55
        v
 
56
      end
 
57
 
 
58
      def [](k)
 
59
        @flash[k]
 
60
      end
 
61
 
 
62
      # Convenience accessor for flash.now[:alert]=
 
63
      def alert=(message)
 
64
        self[:alert] = message
 
65
      end
 
66
 
 
67
      # Convenience accessor for flash.now[:notice]=
 
68
      def notice=(message)
 
69
        self[:notice] = message
 
70
      end
 
71
    end
 
72
 
 
73
    # Implementation detail: please do not change the signature of the
 
74
    # FlashHash class. Doing that will likely affect all Rails apps in
 
75
    # production as the FlashHash currently stored in their sessions will
 
76
    # become invalid.
 
77
    class FlashHash
 
78
      include Enumerable
 
79
 
 
80
      def initialize #:nodoc:
 
81
        @used    = Set.new
 
82
        @closed  = false
 
83
        @flashes = {}
 
84
        @now     = nil
 
85
      end
 
86
 
 
87
      def initialize_copy(other)
 
88
        if other.now_is_loaded?
 
89
          @now = other.now.dup
 
90
          @now.flash = self
 
91
        end
 
92
        super
 
93
      end
 
94
 
 
95
      def []=(k, v) #:nodoc:
 
96
        keep(k)
 
97
        @flashes[k] = v
 
98
      end
 
99
 
 
100
      def [](k)
 
101
        @flashes[k]
 
102
      end
 
103
 
 
104
      def update(h) #:nodoc:
 
105
        h.keys.each { |k| keep(k) }
 
106
        @flashes.update h
 
107
        self
 
108
      end
 
109
 
 
110
      def keys
 
111
        @flashes.keys
 
112
      end
 
113
 
 
114
      def key?(name)
 
115
        @flashes.key? name
 
116
      end
 
117
 
 
118
      def delete(key)
 
119
        @flashes.delete key
 
120
        self
 
121
      end
 
122
 
 
123
      def to_hash
 
124
        @flashes.dup
 
125
      end
 
126
 
 
127
      def empty?
 
128
        @flashes.empty?
 
129
      end
 
130
 
 
131
      def clear
 
132
        @flashes.clear
 
133
      end
 
134
 
 
135
      def each(&block)
 
136
        @flashes.each(&block)
 
137
      end
 
138
 
 
139
      alias :merge! :update
 
140
 
 
141
      def replace(h) #:nodoc:
 
142
        @used = Set.new
 
143
        @flashes.replace h
 
144
        self
 
145
      end
 
146
 
 
147
      # Sets a flash that will not be available to the next action, only to the current.
 
148
      #
 
149
      #     flash.now[:message] = "Hello current action"
 
150
      #
 
151
      # This method enables you to use the flash as a central messaging system in your app.
 
152
      # When you need to pass an object to the next action, you use the standard flash assign (<tt>[]=</tt>).
 
153
      # When you need to pass an object to the current action, you use <tt>now</tt>, and your object will
 
154
      # vanish when the current action is done.
 
155
      #
 
156
      # Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>.
 
157
      def now
 
158
        @now ||= FlashNow.new(self)
 
159
      end
 
160
 
 
161
      # Keeps either the entire current flash or a specific flash entry available for the next action:
 
162
      #
 
163
      #    flash.keep            # keeps the entire flash
 
164
      #    flash.keep(:notice)   # keeps only the "notice" entry, the rest of the flash is discarded
 
165
      def keep(k = nil)
 
166
        use(k, false)
 
167
      end
 
168
 
 
169
      # Marks the entire flash or a single flash entry to be discarded by the end of the current action:
 
170
      #
 
171
      #     flash.discard              # discard the entire flash at the end of the current action
 
172
      #     flash.discard(:warning)    # discard only the "warning" entry at the end of the current action
 
173
      def discard(k = nil)
 
174
        use(k)
 
175
      end
 
176
 
 
177
      # Mark for removal entries that were kept, and delete unkept ones.
 
178
      #
 
179
      # This method is called automatically by filters, so you generally don't need to care about it.
 
180
      def sweep #:nodoc:
 
181
        keys.each do |k|
 
182
          unless @used.include?(k)
 
183
            @used << k
 
184
          else
 
185
            delete(k)
 
186
            @used.delete(k)
 
187
          end
 
188
        end
 
189
 
 
190
        # clean up after keys that could have been left over by calling reject! or shift on the flash
 
191
        (@used - keys).each{ |k| @used.delete(k) }
 
192
      end
 
193
 
 
194
      # Convenience accessor for flash[:alert]
 
195
      def alert
 
196
        self[:alert]
 
197
      end
 
198
 
 
199
      # Convenience accessor for flash[:alert]=
 
200
      def alert=(message)
 
201
        self[:alert] = message
 
202
      end
 
203
 
 
204
      # Convenience accessor for flash[:notice]
 
205
      def notice
 
206
        self[:notice]
 
207
      end
 
208
 
 
209
      # Convenience accessor for flash[:notice]=
 
210
      def notice=(message)
 
211
        self[:notice] = message
 
212
      end
 
213
 
 
214
      protected
 
215
 
 
216
        def now_is_loaded?
 
217
          !!@now
 
218
        end
 
219
 
 
220
        # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods
 
221
        #     use()               # marks the entire flash as used
 
222
        #     use('msg')          # marks the "msg" entry as used
 
223
        #     use(nil, false)     # marks the entire flash as unused (keeps it around for one more action)
 
224
        #     use('msg', false)   # marks the "msg" entry as unused (keeps it around for one more action)
 
225
        # Returns the single value for the key you asked to be marked (un)used or the FlashHash itself
 
226
        # if no key is passed.
 
227
        def use(key = nil, used = true)
 
228
          Array(key || keys).each { |k| used ? @used << k : @used.delete(k) }
 
229
          return key ? self[key] : self
 
230
        end
 
231
    end
 
232
 
 
233
    def initialize(app)
 
234
      @app = app
 
235
    end
 
236
 
 
237
    def call(env)
 
238
      if (session = env['rack.session']) && (flash = session['flash'])
 
239
        flash.sweep
 
240
      end
 
241
 
 
242
      @app.call(env)
 
243
    ensure
 
244
      session    = env['rack.session'] || {}
 
245
      flash_hash = env[KEY]
 
246
 
 
247
      if flash_hash
 
248
        if !flash_hash.empty? || session.key?('flash')
 
249
          session["flash"] = flash_hash
 
250
          new_hash = flash_hash.dup
 
251
        else
 
252
          new_hash = flash_hash
 
253
        end
 
254
 
 
255
        env[KEY] = new_hash
 
256
      end
 
257
 
 
258
      if session.key?('flash') && session['flash'].empty?
 
259
        session.delete('flash')
 
260
      end
 
261
    end
 
262
  end
 
263
end