Form_For Error Messages in Ruby on Rails

form_for error messages in Ruby on Rails

Same as Rails 3 -- see f.error_messages in Rails 3.0 or http://railscasts.com/episodes/211-validations-in-rails-3 for many different possibilities.

My personal preference is to use simple_form and have it put the error next to the input.

Rails 7 signup form doesn't show error messages

If you look at the logs you can see that Rails is getting an AJAX request in the form of a turbo stream:

Processing by UsersController#create as TURBO_STREAM

Where it should read:

Processing by UsersController#create as HTML

To disable turbo you want need to set a data-turbo="false" attribute on the form:

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, data: { turbo: false }) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>

The local: false option only works with the old Rails UJS javascript library which was the default prior to Rails 7. You can also disable Turbo by default with:

import { Turbo } from "@hotwired/turbo-rails"
Turbo.session.drive = false

See:

https://turbo.hotwired.dev/handbook/drive#disabling-turbo-drive-on-specific-links-or-forms

Showing form error messages

Errors

The problem isn't anything to do with the way you're rendering the form (render or redirect) - it's to do with the way you're handling your ActiveRecord object.

When you use form_for, Rails will append any errors into the @active_record_object.errors method. This will allow you to call the following:

form_for error messages in Ruby on Rails

<%= form_for @object do |f| %>
<% @location.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>

This only works if you correctly create your ActiveRecord object, which you seem to do

--

Nested

#config/routes.rb
resources :topics do
resources :posts, path: "", path_names: {new: ""}, except: [:index] #-> domain.com/topics/1
end

You'll be much better using the following setup for a nested route:

<%= form_for [@topic, @post] do |f| %>
...
<% end %>

This allows you to create a form which will route to the topics_posts_path, which is basically what you need. The controller will then balance that by using the following:

#app/controllers/topics_controller.rb
Class TopicsController < ApplicationController
def new
@topic = Topic.find params[:topic_id]
@post = Post.new
end
def create
@topic = Topic.find params[:topic_id]
@post = Post.new post_params
end

private

def post_params
params.require(:post).permit(:attributes)
end
end

Why does simple form not show validation error messages in Rails?

You're not binding the @comment instance you have created in your controller to the form. Instead @recipe.comments.build always creates a new instance of Comment.

You can set the model with a conditional:

<%= simple_form_for([@recipe, @comment || @recipe.comments.build]) do |form| %> 
<%= f.error_notification %>
<%= f.object.errors.full_messages.join(", ") if f.object.errors.any? %>
<%= f.input :name, label: false, placeholder: "Your name" %>
<%= f.input :comment, label: false, placeholder: "Tell us about your experience" %>
<%= f.submit "Submit", class: "btn-comment-submit" %>
<% end %>

Note that you don't need to set the values for the inputs. The form builder will do that for you. Thats kind of the whole point of it.

Or you can preferably ensure that you're setting @comment in the controller to keep the view as simple as possible:

class RecipiesController < ApplicationController
before_action :set_recipe
# ...
def show
@comment = @recipe.comments.new
end

# ...
end
<%= simple_form_for([@recipe, @comment]) do |form| %>
# ...
<% end %>

And you can clean up your create action and just create the comment off the recipe:

def create
@recipe = Recipe.find(params[:recipe_id])
@comment = @recipe.comments.new(comment_params)
if @comment.save
redirect_to @recipe
else
render :new
end
end

Form Error Messages Not Generating in Rails App

As I said, you need to change

redirect_to '/signup' 

to

render 'new'

From the Guides

The render method is used so that the @user object is passed back
to the new template when it is rendered. This rendering is done within
the same request as the form submission, whereas the redirect_to will
tell the browser to issue another request.

That said, so as the redirect_to issues a new request to the browser, the values of @user is lost, in other words @user is a new instance that is instantiated again. That is why <% if @user.errors.any? %> always returns false as if there are no errors in @user.



Related Topics



Leave a reply



Submit