The Rails flash isn't just for messages

Written . Tagged Ruby on Rails.

The Rails flash is typically used for short messages:

app/controllers/sessions_controller.rb
1
redirect_to root_url, notice: "You have been logged out."

But it can be used for more than that, any time that you redirect and want to pass along some state without making it part of the URL.

These are some things I’ve used it for.

Identifiers for more complex messages

Maybe you want to show a more complex message after signing up, containing things like links and bullet points.

Rather than send all that in the flash, you can send some identifier that your views know how to handle.

This could be the name of a partial:

app/controllers/users_controller.rb
1
2
3
4
5
6
7
class UsersController < ApplicationController
  def create
    @user = actually_create_user
    flash[:partial] = "welcome"
    redirect_to some_path
  end
end
app/views/layouts/application.html.haml
1
2
- if flash[:partial]
  = render partial: "shared/flashes/#{flash[:partial]}"
app/views/shared/flashes/_welcome.html.haml
1
2
3
4
%p Welcome!
%ul
  %li= link_to("Do this!", this_path)
  %li= link_to("Do that!", that_path)

Or just a flag:

app/controllers/users_controller.rb
1
2
flash[:signed_up] = true
redirect_to root_path
app/views/welcomes/show.html.haml
1
2
- if flash[:signed_up]
  %p Welcome!

Pass on the referer

Say you have some filter redirecting incoming requests. Maybe you’re detecting the locale and adding it to the URL, or verifying credentials.

You can use the flash to make sure the redirected-to controller gets the original referer.

app/controllers/application_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ApplicationController < ActionController::Base
  before_filter :keep_original_referer
  before_filter :make_locale_explicit

  private

  def make_locale_explicit
    if params[:locale].blank? && request.get?
      redirect_to params.merge(locale: I18n.locale)
    end
  end

  def keep_original_referer
    # Don't overwrite existing value, for redirect chains.
    flash[:original_referer] ||= request.referer
  end

  def original_referer
    flash[:original_referer]
  end
end

Now, any controller that cares about the referer could get it with original_referer.

Google Analytics events

Say you want to track a Google Analytics event event with JavaScript when a user has signed up. You could do something like this.

Send event data from the controller:

app/controllers/users_controller.rb
1
2
3
4
5
6
7
class UsersController < ApplicationController
  def create
    @user = actually_create_user
    flash[:events] = [ ["_trackEvent", "users", "signup"] ]
    redirect_to some_path
  end
end

Then turn it into JavaScript in your view:

app/helpers/layout_helper.rb
1
2
3
4
5
def analytics_events
  Array(flash[:events]).map do |event|
    "_gaq.push(#{raw event.to_json});"
  end.join("\n")
end
app/views/layouts/application.html.haml
1
2
:javascript
  = analytics_events

The flash vs. params

You may have considered that any of the above could have be done with query parameters instead. Including common flash messages:

app/controllers/sessions_controller.rb
1
redirect_to root_url(notice: "You have been logged out.")
app/views/layouts/application.html.haml
1
2
- if params[:notice]
  %p= params[:notice]

Using the flash means that the passed data doesn’t show in the URL, so it won’t happen twice if the link is shared, bookmarked or reloaded. Also the URL will be a little cleaner.

Additionally, the user can’t manipulate the flash, as it’s stored in the session. This adds some protection. If the flash partial example above used params, a user could pass in ../../admin/some_partial to see things they shouldn’t.

Fin

I’d love to hear about what unconventional uses you’ve put the flash to!