Rendering a view after form submission not working correctly in Rails 7

Viewed 847

I have set up a tableless model as described in the Rails v7 guides:

class ContactForm
    include ActiveModel::Model
  
    attr_accessor :name, :email, :message
    validates :name, :email, :message, presence: true

end

I have set up an action to check if the submitted content is valid and send the email if it is:

  def contact_process 
    @contact_form = ContactForm.new(contact_form_params)
    
    if @contact_form.valid?
      UserMailer.with(@contact_form).contact_form.deliver_later 
      redirect_to contact_path
    else  
      render :contact
    end 
  end 

When there are errors and the contact template is rendered again @contact_form seems to be a blank ContactForm instance and for example @contact_form.errors.count returns 0 even though it was printing the correct number in the console just before the render command.

1 Answers

The problem was due to trying to render a page following a form submission with a 200 rather than a 4xx or 5xx code. A 422 code can be added as follows and is recommended when there's a problem with a model:

render 'contact', status: :unprocessable_entity

Rails 7 ships with Turbo. It expects a form submission to be followed by a 303 code redirect, one exception to this being when you need to render validation errors. Here is how it handles form submission, and why a render command on its own isn't going to work and you're probably going to just get some version of the previous page:

Turbo Drive handles form submissions in a manner similar to link clicks. The key difference is that form submissions can issue stateful requests using the HTTP POST method, while link clicks only ever issue stateless HTTP GET requests.

After a stateful request from a form submission, Turbo Drive expects the server to return an HTTP 303 redirect response, which it will then follow and use to navigate and update the page without reloading.

The exception to this rule is when the response is rendered with either a 4xx or 5xx status code. This allows form validation errors to be rendered by having the server respond with 422 Unprocessable Entity and a broken server to display a “Something Went Wrong” screen on a 500 Internal Server Error.

The reason Turbo doesn’t allow regular rendering on 200 is that browsers have built-in behavior for dealing with reloads on POST visits where they present a “Are you sure you want to submit this form again?” dialogue that Turbo can’t replicate. Instead, Turbo will stay on the current URL upon a form submission that tries to render, rather than change it to the form action, since a reload would then issue a GET against that action URL, which may not even exist.

Related