Flash messages with Turbo Streams (Bootstrap Alert)
-
Source Repository: https://github.com/swobspace/rails-playground
-
Bootstrap v5 Alert: https://getbootstrap.com/docs/5.1/components/alerts
-
Rails Playground: used in lists on add/remove tasks, not on updates. For updates we use Bootstrap Toast (see Flash messages with Turbo Streams (Bootstrap Toast))
The goal: show flash messages from turbo_stream rendering with animation, fadeout and remove it after the animation has finished
Rails controller: set the flash message
def create
@task = @list.tasks.build(task_params)
respond_with(@task, location: location) do |format|
if @task.save
format.turbo_stream { flash.now[:notice] = "Task successfully created" }
end
end
end
We use flash.now here since there is no redirect with turbo_stream.
|
respond_with since we uses the responders gem from https://github.com/heartcombo/responders. Your mileage may vary. Plain rails 7 generators don’t use respond_to (nor respond_with ). See app/controllers/categories_controller.rb .
|
Layout
Very simple: just a <div>
with an id
where to show flash messages from turbo_stream rendering. Otherwise render existing flashes as usual. In case of turbo_stream rendering the content of the <div>
will be replaced by turbo_stream content.
<div class="container-fluid">
<div id="flash"> (1)
<%= render "shared/flash_alert" %>
</div>
<%= yield %>
</div>
1 | id for turbo_stream replacing |
A Helper to render Turbo Alerts
A helper to call from each create|update|destroy.turbo_stream.erb
view: simply add the following snippet to each view:
<%= render_turbo_flash %>
A view component for alerts
Since flashes goes with keys like :alert, :error, :notice, we need those translated in Bootstrap jargon like 'danger', 'info' or 'success'.
# frozen_string_literal: true
class AlertComponent < ViewComponent::Base
def initialize(severity:, message:)
@level = update_severity(severity)
@message = message
end
private
# bootstrapify names
def update_severity(severity)
case severity.to_sym
when :alert, :error
"danger"
when :notice
"info"
else
severity.to_s
end
end
end
<div class="alert alert-<%= @level %> alert-dismissable fadeout" role="alert"
data-controller="remove"
data-action="animationend->remove#remove"
>
<span><%= @message %></span>
<button type="button" class="btn-close float-end" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
CSS for animating flash messages
// -- animation: fadeout for flash messages
.fadeout {
animation: 4s fadeout;
}
@keyframes fadeout {
0%, 100% { opacity: 0; }
10%, 50% { opacity: 1; }
}
More information on css animations can be found on https://developer.mozilla.org/de/docs/Web/CSS/animation |