Skip to content

Commit

Permalink
Move Flash into middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
josh committed Jan 15, 2010
1 parent 3da29f6 commit ead93c5
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 183 deletions.
2 changes: 1 addition & 1 deletion actionpack/lib/action_controller/metal/compatibility.rb
Expand Up @@ -31,7 +31,7 @@ class << self
@variables_added @request_origin @url
@parent_controller @action_name
@before_filter_chain_aborted @_headers @_params
@_flash @_response)
@_response)

# Controls the resource action separator
cattr_accessor :resource_action_separator
Expand Down
177 changes: 2 additions & 175 deletions actionpack/lib/action_controller/metal/flash.rb
@@ -1,187 +1,14 @@
module ActionController #:nodoc:
# The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed
# to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
# action that sets <tt>flash[:notice] = "Successfully created"</tt> before redirecting to a display action that can
# then expose the flash to its template. Actually, that exposure is automatically done. Example:
#
# class PostsController < ActionController::Base
# def create
# # save post
# flash[:notice] = "Successfully created post"
# redirect_to posts_path(@post)
# end
#
# def show
# # doesn't need to assign the flash notice to the template, that's done automatically
# end
# end
#
# show.html.erb
# <% if flash[:notice] %>
# <div class="notice"><%= flash[:notice] %></div>
# <% end %>
#
# 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
extend ActiveSupport::Concern

included do
delegate :flash, :to => :request
delegate :alert, :notice, :to => "request.flash"
helper_method :alert, :notice
end

class FlashNow #:nodoc:
def initialize(flash)
@flash = flash
end

def []=(k, v)
@flash[k] = v
@flash.discard(k)
v
end

def [](k)
@flash[k]
end
end

class FlashHash < Hash
def initialize #:nodoc:
super
@used = Set.new
end

def []=(k, v) #:nodoc:
keep(k)
super
end

def update(h) #:nodoc:
h.keys.each { |k| keep(k) }
super
end

alias :merge! :update

def replace(h) #:nodoc:
@used = Set.new
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.discard # discard the entire flash at the end of the current action
# flash.discard(:warning) # discard only the "warning" entry at the end of 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.include?(k)
@used << k
else
delete(k)
@used.delete(k)
end
end

# clean up after keys that could have been left over by calling reject! or shift on the flash
(@used - keys).each{ |k| @used.delete(k) }
end

def store(session)
return if self.empty?
session["flash"] = self
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)
# Returns the single value for the key you asked to be marked (un)used or the FlashHash itself
# if no key is passed.
def use(key = nil, used = true)
Array(key || keys).each { |k| used ? @used << k : @used.delete(k) }
return key ? self[key] : self
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:
unless @_flash
@_flash = session["flash"] || FlashHash.new
@_flash.sweep
end

@_flash
end

# Convenience accessor for flash[:alert]
def alert
flash[:alert]
end

# Convenience accessor for flash[:alert]=
def alert=(message)
flash[:alert] = message
end

# Convenience accessor for flash[:notice]
def notice
flash[:notice]
end

# Convenience accessor for flash[:notice]=
def notice=(message)
flash[:notice] = message
end

protected
def process_action(method_name)
@_flash = nil
super
@_flash.store(session) if @_flash
@_flash = nil
end

def reset_session
super
@_flash = nil
end

def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
if alert = response_status_and_flash.delete(:alert)
flash[:alert] = alert
Expand Down
4 changes: 3 additions & 1 deletion actionpack/lib/action_controller/test_case.rb
Expand Up @@ -239,13 +239,15 @@ def process(action, parameters = nil, session = nil, flash = nil, http_method =
@request.assign_parameters(@controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)

@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
@request.session["flash"] = @request.flash.update(flash || {})
@request.session["flash"].sweep

@controller.request = @request
@controller.params.merge!(parameters)
build_request_uri(action, parameters)
Base.class_eval { include Testing }
@controller.process_with_new_base_test(@request, @response)
@request.session.delete('flash') if @request.session['flash'].blank?
@response
end

Expand Down
1 change: 1 addition & 0 deletions actionpack/lib/action_dispatch.rb
Expand Up @@ -43,6 +43,7 @@ module ActionDispatch
autoload_under 'middleware' do
autoload :Callbacks
autoload :Cascade
autoload :Flash
autoload :Head
autoload :ParamsParser
autoload :Rescue
Expand Down
4 changes: 0 additions & 4 deletions actionpack/lib/action_dispatch/http/request.rb
Expand Up @@ -463,10 +463,6 @@ def session_options=(options)
@env['rack.session.options'] = options
end

def flash
session['flash'] || {}
end

# Returns the authorization header regardless of whether it was specified directly or through one of the
# proxy alternatives.
def authorization
Expand Down

0 comments on commit ead93c5

Please sign in to comment.