DEV Community

Rob Bazinet
Rob Bazinet

Posted on • Originally published at accidentaltechnologist.com on

How to Fix Rails Flash Rendering When Using Hotwire

I added Hotwire to a Ruby on Rails application I’ve been working on and discovered some issues when rendering flash messages. Yesterday I wrote about problems related to CORS error using OmniAuth. Today’s is not as exciting but still as annoying.

Problem

I was in the process of testing some validation changes I implemented and realized errors were not being displayed. I went through the typical debug scenarios and found that errors were being returned but just not displayed.

The code consists of just trying to create a user:

def create
  @user = User.new(user_params)
  if @user.save
    redirect_to root_path, notice: “User created successfully“
  else
    render :new
  end
end
Enter fullscreen mode Exit fullscreen mode

When creating a user, the new form rendered but errors were not displayed.

Solution

The reason the messages were not being displayed is because of Turbo and Rails UJS conflicting. Solving the problem can be done in one of two ways.

  1. It appears Turbo expects form submissions to redirect to a new location. When there is an error, we are staying on the same page. Adding status: :unprocessable_entity to the render fixes the problem.
def create
  @user = User.new(user_params)
  if @user.save
    redirect_to root_path, notice: “User created successfully“
  else
    render :new, status: :unprocessable_entity 
  end
end
Enter fullscreen mode Exit fullscreen mode
  1. A similar solution from yesterday’s post also works. Adding
data: { turbo: false }
Enter fullscreen mode Exit fullscreen mode

The form declaration disables turbo and lets Rails UJS handle as desired.

I hope future versions of Turbo handle this better.

The post How to Fix Rails Flash Rendering When Using Hotwire appeared first on Accidental Technologist.

Top comments (3)

Collapse
 
anke1460 profile image
aws

I used it like this:
controller

flash.now[:error] = "some errors"
render turbo_stream: turbo_stream.replace("flash_alert", partial: "layouts/flash", locals: { flash: flash }) 
Enter fullscreen mode Exit fullscreen mode

view

<%= turbo_frame_tag "flash" do %>
   <%= render "layouts/flash" %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

layouts/_flash.html.erb:

<div id="flash_alert">
   <% flash.each do |type, message| %>
      <%= message %>
   <% end %>
</div>
Enter fullscreen mode Exit fullscreen mode
Collapse
 
superails profile image
Yaroslav Shmarov

why would you want to use turbo_stream.replace rather than turbo_stream.update?

Collapse
 
fmarkwong profile image
developer dude

I just had it redirect to root_path (or whatever path you like) on error just like with the happy path.

Any problems with this solution? I guess the disadvantage is an extra redirect.