Handling Create and Update Operations with Turbo Streams in Rails 7 (rspec tests included)

Handling Create and Update Operations with Turbo Streams in Rails 7 (rspec tests included)

TL;DR

post searches_url, params: { search: invalid_attributes }, as: :turbo_stream

I have recently implemented CRUD(Create, Read, Update, Delete) operations using Rails 7. There are multiple methodologies for creating and updating records. One such method involves the deactivation of Turbo within the form. Consider the following example:

<%= form_with model: search, html: { data: { turbo: false } } do |f| %>
<% end %>

Following this configuration in your form, your controller can respond either with an HTML format or redirect upon successful operation completion.

An alternative method for creating and updating records involves the use of turbo_stream for handling failure responses. Rails 7 defaults to the turbo_stream format the form submissions. Consequently, it's essential that your controller responds in the turbo_stream format as well.

Here is my implementation of this:

def create # rubocop:disable Metrics/AbcSize
    result = Searches::Create.new(current_user:, params: search_params).call
    if result.success?
      redirect_to search_url(result.success[:search]), notice: 'Wyszukiwanie zostało utworzone.'
    else
      flash.now[:error] = result.failure[:message]
      render 'searches/update', locals: { search: result.failure[:search] }
    end
  end

In the instance of failure, the 'searches/update' template, a turbo_stream extension, is rendered. The corresponding file for this extension is 'update.turbo_stream.erb' In this file, I update both the form and flash components:

# app/views/searches/update.turbo_stream.erb
<%= turbo_stream.replace(search, partial: 'searches/form', locals: { search: }) %>
<%= turbo_stream.update('flashes_component') do %>
  <%= render FlashesComponent.new(flash: flash, position: 'bottom-right') %>
<% end %>

Tests

To thoroughly test these requests, I created tests for both HTML and turbo_stream formats. Here's how you can test a request with an HTML format:

context 'with invalid parameters' do
    it 'renders a new template' do
        post searches_url, params: { search: invalid_attributes }
        expect(response).to render_template('searches/update')
        expect(response.body).to include('Nie udało się utworzyć wyszukiwania. Popraw dane w formularzu.')
    end
end

In contrast, to test the turbo_stream format, you'll need to send the request in the corresponding format:

post searches_url, params: { search: invalid_attributes }, as: :turbo_stream

These implementation and testing strategies should equip you well for setting up your CRUD operations in Rails 7.

Lastly, I've included a GIF to visually demonstrate how errors are handled using turbo_stream.