← Go back to the home page

Inlining flash messages with the redirect() call in Laravel

Say you're creating an admin dashboard for a blog. When the user saves a post, you want to redirect to the posts index and display a success message to the user. Wouldn't it be cool if you could do all of that in one line?

First lets go through some ways to achieve this functionality.

TL;DR: go to the final solution.

Quick & dirty

We put this code in the PostsController:

public function store(Request $request)
{
    Post::create($request->only(['title', 'body']));

    session()->flash('message', 'Post was created!');

    return redirect()->route('posts.index');
}

We create the post in the database. Then we store the message Post was created! in the session. We use the flash() method so that the message key will only be available during the next HTTP request and then it will be deleted. Then we redirect to the posts index page.

We put this code somewhere in the app.blade.php layout file:

@if (session()->has('message'))
    <div class="alert alert-info">
        {{ session('message') }}
    </div>
@endif

We use the global session() helper and its has() method to determine whether there is a message stored in the session. If so, we display it to the user, using the standard Bootstrap alert component.

It works fine, but we can do better.

Using the laracasts/flash package

This functionality is so common that Jeffrey Way from Laracasts created a package for it. It's super simple to use. For installation details, follow the readme at the Github repository.

Here's how we can change our PostsController to make use of the package:

public function store(Request $request)
{
    Post::create($request->only(['title', 'body']));

    flash('Post was created!');

    return redirect()->route('posts.index');
}

We also need to change the app.blade.php file:

@if (session()->has('flash_notification.message'))
    <div class="alert alert-{{ session('flash_notification.level') }}">
        {!! session('flash_notification.message') !!}
    </div>
@endif

The cool thing is that we can set the contextual class of the alert. By default it's set as info, but if you change the middle line of our PostsController@store method to flash('Post was created!', 'success') the alert will get a green background indicating successful action.

Ok, this is nice, but wouldn't it be cool if we could inline the flash() call with the return redirect() call?

Using the RedirectResponse

Lets go back to using what Laravel gives us by default.

Lets change the PostsController to this:

public function store(Request $request)
{
    Post::create($request->only(['title', 'body']));

    return redirect()->route('posts.index')->with('message', 'Post was created!');
}

When we call the redirect() global helper, we get back an instance of RedirectResponse. We can flash data to the session by chaining the with() method to the redirect() call.

Lets change our app.blade.php file back to this:

@if (session()->has('message'))
    <div class="alert alert-info">
        {{ session('message') }}
    </div>
@endif

The controller method looks better, but we lost the ability to set the class of the alert. Or have we? We can chain more with() methods to the redirect() call. Lets change the last line of the PostsController@store method to this:

return redirect()->route('posts.index')->with('flash.message', 'Post was created!')->with('flash.class', 'success');

And our app.blade.php file to this:

@if (session()->has('flash.message'))
    <div class="alert alert-{{ session('flash.class') }}">
        {{ session('flash.message') }}
    </div>
@endif

Ok, lets recap. We shortened the controller method and we were able to retain the ability to set the css class of the alert. Cool, but this line has become rather long and untidy:

return redirect()->route('posts.index')->with('flash.message', 'Post was created!')->with('flash.class', 'success');

What if instead we could write something like:

return redirect()->route('posts.index')->withSuccessMessage('Post was created!');

Feels better, right?

Extending the RedirectResponse

The RedirectResponse class that we get when we use the redirect() helper is macroable. What that means is that we can easily add our custom withSuccessMessage method to it.

Lets add this to our AppServiceProvider:

public function boot()
{
    RedirectResponse::macro('withSuccessMessage', function ($message) {
        return RedirectResponse::with('flash.message', $message)->with('flash.class', 'success');
    });
}

That's it. Now our controller method can look like this:

public function store(Request $request)
{
    Post::create($request->only(['title', 'body']));

    return redirect()->route('posts.index')->withSuccessMessage('Post was created!');
}