Flash Messages with Lucky
Tags: lucky, crystal
Published: 2020-12-26 05:56:29

There's often a need to show users some dynamic message based on some process of the app or action on their part. The most common scenario is usually around submitting forms. The user is trying to sign in to the app but use an incorrect password so the app sends them an error flash telling them to please try again. They subsequently sign in successfullyi so the app sends them a happy success flash welcoming them back 🌈🦄. But how might you do this in your Lucky app? Let's check it out.

## Adding a flash message

Going back to the form scenario, to add a flash message based on the outcome of a save operation it might look like:

```crystal
class Users::Create < BrowserAction
  post "/user" do
    SaveUser.create(params) do |op, user|
      if op.saved?
        flash.success = "User created!"
        redirect to: Users::Show.with(user.id)
      else
        flash.failure = "Something went wrong..."
        html Users::NewPage, operation: op
      end
    end
  end
end
```

This action is to create a new `User` and renders a success flash message if it worked and a failure message if it failed to create the user. Besides `flash.success` and `flash.failure`, there is also `flash.info` for general information to pass to the user. If you need a custom flash key and message you can call `flash.set(:some_key, "some value")`.

Once a flash is set, it is accessible for the rest of the request or in the next one. The flash will be removed after that. It's so that, as in this example action, flashes can survive redirects. If you need the flash to survive longer than that, I will explain how to do it later in the post.

## Accessing flash messages

While flashes are a way to pass information across stateless requests, the most common use for them is for rendering HTML to notify users of events. Here's an example of something you might have in a component or a page to display flash messages if their are any:

```crystal
flash.each do |type, message|
  div class: "alert alert-#{type}", role: "alert" do
    para message
  end
end
```

This iterates over every plash and displays the message to the user. When they refresh the page it will be gone. This is a nice and simple way to send the user short-lived informational messages. Much like we set them above, flashes can also be accessed individually. You can call `flash.get?(:any_key)` to get a message if there is one. There is also helpers for the predefined message types so `flash.info?` will work as well. This is useful if you display different flash message types in different ways.

## Other Usefulness

### Persisting flash messages for multiple requests

Flash messages are only kept for the request they were set in and the next one, but sometimes you need to persist them for longer. To do this, you can call `flash.keep` to persist any flash messages given to the current request onto future ones. The most common use-case for this is when redirecting requests, but [Lucky already handles this scenario for you](https://github.com/luckyframework/lucky/blob/0b9be66ab1e0c238aa8715cdb3b195ceae59459b/src/lucky/redirectable.cr#L124).

It's important to remember to only call `flash.keep` when you know you need to pass flash messages onto future requests. Calling it outside this scenario can lead to flash messages appearing to the user multiple times.

### Clearing flash messages

I think the heading says enough. Just call `flash.clear` to immediately remove all existing flash messages.

## One Warning

It's important to remember that flash messages are accessible in the request they are set in **AND** the next one. If you render all flash messages in HTML if there are any, setting flash messages on requests that don't redirect can also lead to them appearing to the user multiple times. For example, if you set a flash message on the user's profile page, they will see the flash message and then it will render again if they go to the home page.

Unfortunately, there's not a solution for this problem right now but keep an eye on this issue to know when we have a working solution. {% github https://github.com/luckyframework/lucky/issues/1271 %}