Skip to content

Instantly share code, notes, and snippets.

@coreyti
Created September 27, 2012 06:13
Show Gist options
  • Save coreyti/3792471 to your computer and use it in GitHub Desktop.
Save coreyti/3792471 to your computer and use it in GitHub Desktop.
Add resource-scoped flash to Devise; SimpleForm-based scoped message output
### in Rails.root.join('app/views/layouts/application.html.erb')
# render `flash[:alert]` and `flash[:notice]`, if unclaimed (by a scoped usage)
<body>
<p class="alert alert-error">
<%= flash[:alert] %>
</p>
<p class="alert alert-info">
<%= flash[:notice] %>
</p>
<!-- stuff... -->
<body>
### in Rails.root.join('config/initializers/auth.rb')
# define custom FailureApp for Devise to add indication of scoped flash messages.
# the point here is, when Warden invalidates a session#create attempt, it exits
# quickly and before loading the resource. hence, Devise cannot place errors on
# a resource. instead, it resorts to using the `flash`. so, we add a workaround.
module MyAppName
module Auth
class FailureApp < Devise::FailureApp
def recall
flash.now[scope] = [:alert]
super
end
end
end
end
### in Rails.root.join('config/initializers/devise.rb')
# update Devise setup to use custom FailureApp.
Devise.setup do |config|
# stuff...
config.warden do |manager|
manager.failure_app = MyAppName::Auth::FailureApp
end
# stuff...
end
### in Rails.root.join('config/initializers/form.rb')
# define custom FormBuilder and set it as default.
module MyAppName
class FormBuilder < SimpleForm::FormBuilder
# look for scoped flash message keys: `flash[:user] = [:alert, :notice]`.
# if found and for each key, capture and delete matching message from
# top-level flash. build html to render the message.
def flash(*args)
template.flash[object_name] ||= []
mapping = { :alert => :error, :notice => :info }
args.map do |arg|
if template.flash[object_name].include?(arg)
message = (text = template.flash[arg]) && template.flash.delete(arg) && text
html = <<-HTML
<p class="alert alert-#{mapping[arg]}">
<strong>#{arg}:</strong>
#{message}
<button type="button" class="close" data-dismiss="alert">x</button>
</p>
HTML
end
end.join.html_safe
end
end
end
ActionView::Base.default_form_builder = MyAppName::FormBuilder
### in Rails.root.join('app/views/users/sessions/new.html.erb')
# use FormBuilder#flash to render messages.
<h2>Sign in</h2>
<%= form_for(resource, {
:as => resource_name,
:url => session_path(resource_name)
}) do |f| %>
<%#
if, e.g., `flash[:user]` is `[:alert]`, we use up, the
`flash[:alert]` message here. otherwise, leave it for top-level access.
%>
<%= f.flash(:alert, :notice) %>
<div class="form-inputs">
<%= f.input :email, :required => false, :autofocus => true %>
<%= f.input :password, :required => false %>
<%= f.input :remember_me, :as => :boolean if devise_mapping.rememberable? %>
</div>
<div class="form-actions">
<%= f.button :submit, "Sign in" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment