After fixing validation errors, errors are still shown

Hi,
I am developing a 2-step booking system. The first step is for choosing start and end dates (which are attributes of a model called BookingDate. Second step for choosing the bookable items.
I want to persist the BookingDate when the user presses a button, and still show the editable date inputs after persisting the record.
Everything works fine, except when there are validation errors. After the user corrects the dates and persists the record, the error message is still shown.

index.html.erb

<%= turbo_frame_tag BookingDate.new do %>
  <%= render "booking_dates_form", booking_date: @booking_date %>
<% end %>

_booking_dates_form.html.erb

<%= turbo_frame_tag BookingDate.new do %>
  <%= form_with(model: booking_date, url: "cust/booking_dates", scope: :booking_date) do |f| %>
    <% if booking_date.errors.any? %>
      ...
    <% end %>

    <%= f.date_field :start_date %>
    <%= f.date_field :end_date %>
    <%= f.submit value = "Next step", class: "btn btn-primary", data: { turbo_frame: "customer_bikes" } %>
  <% end %>
<% end %>

home_controller.rb

def create_booking_date
  @booking_date = BookingDate.new(booking_date_params)
  respond_to do |format|
    if @booking_date.save
      format.html { render :edit_booking_date, status: :ok, location: @booking_date }
    else
      format.html { render :new_booking_date, status: :unprocessable_entity }
    end
  end
end

Not sure if this is the problem but you have duplicated turbo_frame_tag BookingDate.new It is both in index and the partial.

1 Like

This is intended, the turbo_frame in the partial contains the updated content.

I understand some information are still missing:

home_controller.rb

def edit_booking_date
  @booking_date = BookingDate.new(booking_date_params)  
end

edit_booking_date.html.erb

<%= turbo_frame_tag BookingDate.new do %>
  <%= render "cust/home/booking_dates_form", booking_date: @booking_date %>
<% end %>

routes.rb

post "cust/booking_dates", to: "cust/home#create_booking_date"
patch "cust/booking_dates", to: "cust/home#edit_booking_date"
root "cust/home#index"

Finally, it has to be mentioned that I also tried to turbo-redirect to the home page, instead of rendering the edit_booking_date action, but nothing changed: after a correct save/patch, the @booking_date.errors is empty, but the part of the web page displaying them is not refreshed, hence they are still visible.

home_controller.rb

      format.html { redirect_to "/", notice: "dates created" }
#     format.html { render :edit_booking_date, status: :ok, location: @booking_date }

Just to rule it out, try making that DOM ID for the frame manually. When you base the frame id on an object, then once that object gets persisted, it will have a (database) ID and its DOM ID will change. This mis-match could be the issue with your page not updating as you expect.

In contrast, if you try <%= turbo_frame_tag 'booking_form' %> in both the starting page and the replacement, then the update will move into the correct form, because the IDs will match.

If you have more than one of these on the page, then they will each need a unique ID, naturally.

Walter

1 Like

Indeed, tag BookingDate.new always returns “new_booking_date”, despite the record being new or persisted.

At the end, I managed to fix my code, there were a number of errors. In a snapshot:

routes.rb

  patch "cust/booking_dates/:id", to: "cust/home#update_booking_date"
  post "cust/booking_dates", to: "cust/home#create_booking_date"
  get "cust/booking_dates/:id", to: "cust/home#edit_booking_date"
  get "cust/booking_dates/:id/edit", to: "cust/home#edit_booking_date"

cust/home_controller.rb

    def create_booking_date
      respond_to do |format|
        if @booking_date.save
          format.html { redirect_to "/cust/booking_dates/%s" % (@booking_date.id), notice: "Dates created" }
        else
          format.html { render :new_booking_date, status: :unprocessable_entity }
        end
      end
    end

    def update_booking_date
      respond_to do |format|
        if @booking_date.update(booking_date_params)
          format.html { redirect_to "/cust/booking_dates/%s" % (@booking_date.id), notice: "Dates updated" }
        else
          format.html { render :edit_booking_date, status: :unprocessable_entity }
        end
      end
    end

cust/home/booking_dates_form.html.erb

<%= turbo_frame_tag BookingDate.new do %>
  <% url = "/cust/booking_dates%s" % (booking_date.new_record? ? "" : ("/%s" % booking_date.id) ) %>
  <%= form_with(model: booking_date, url: url, scope: :booking_date) do |f| %>
...
  <% end %>
<% end %>

The url in the form was necessary because the controller is not the “standard” one.

In the end the duplicated turbo_frame_tag was necessary in order to have a one-age application.