How to Display Ruby on Rails Form Validation Error Messages One At a Time

How do I display Ruby on Rails form validation error messages one at a time?

After experimenting for a few hours I figured it out.

<% if @user.errors.full_messages.any? %>
<% @user.errors.full_messages.each do |error_message| %>
<%= error_message if @user.errors.full_messages.first == error_message %> <br />
<% end %>
<% end %>

Even better:

<%= @user.errors.full_messages.first if @user.errors.any? %>

Rails displaying validation messages on form

You should render the 'new' action if the saving fails:

def create
@project = Project.find(params[:project_id])
@datum = @project.build(datum_params)

respond_to do |format|
if @datum.save
format.html { redirect_to project_data_path, notice: 'Created.' }
else
format.html { render action: 'new' }
end
end
end

Also you should change your form to use the @datum instance variable instead building it in the form:

<%= bootstrap_form_for([@project, @datum]) do |f| %>

and the controller:

def new
@project = Project.find(params[:project_id])
@datum = @project.data.build
end

The basic idea is that if the user arrives to the new page you create a new empty datum instance variable. The user fills out the form and posts it to the create action. If the saving fails in the create action, you keep your filled-out @datum object and render that back to the form. The @datum object will have the errors ( you can check by @datum.errors ) which you can display to the user.

Rails validation error messages: Displaying only one error message per field

Bert over at RailsForum wrote about this a little while back. He wrote the code below and I added some minor tweaks for it to run on Rails-3.0.0-beta2.

Add this to a file called app/helpers/errors_helper.rb and simply add helper "errors" to your controller.

module ErrorsHelper

# see: lib/action_view/helpers/active_model_helper.rb
def error_messages_for(*params)
options = params.extract_options!.symbolize_keys

objects = Array.wrap(options.delete(:object) || params).map do |object|
object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model)
object = convert_to_model(object)

if object.class.respond_to?(:model_name)
options[:object_name] ||= object.class.model_name.human.downcase
end

object
end

objects.compact!
count = objects.inject(0) {|sum, object| sum + object.errors.count }

unless count.zero?
html = {}
[:id, :class].each do |key|
if options.include?(key)
value = options[key]
html[key] = value unless value.blank?
else
html[key] = 'errorExplanation'
end
end
options[:object_name] ||= params.first

I18n.with_options :locale => options[:locale], :scope => [:errors, :template] do |locale|
header_message = if options.include?(:header_message)
options[:header_message]
else
locale.t :header, :count => count, :model => options[:object_name].to_s.gsub('_', ' ')
end

message = options.include?(:message) ? options[:message] : locale.t(:body)

error_messages = objects.sum do |object|
object.errors.on(:name)
full_flat_messages(object).map do |msg|
content_tag(:li, ERB::Util.html_escape(msg))
end
end.join.html_safe

contents = ''
contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
contents << content_tag(:p, message) unless message.blank?
contents << content_tag(:ul, error_messages)

content_tag(:div, contents.html_safe, html)
end
else
''
end
end

####################
#
# added to make the errors display in a single line per field
#
####################
def full_flat_messages(object)
full_messages = []

object.errors.each_key do |attr|
msg_part=msg=''
object.errors[attr].each do |message|
next unless message
if attr == "base"
full_messages << message
else
msg=object.class.human_attribute_name(attr)
msg_part+= I18n.t('activerecord.errors.format.separator', :default => ' ') + (msg_part=="" ? '': ' & ' ) + message
end
end
full_messages << "#{msg} #{msg_part}" if msg!=""
end
full_messages
end

end

Rails 5 - Custom validation with one error message

You can write custom validator:

validate :validate_floor

private

def validate_floor
return if floor.present? && floor.scan(/\D/).empty? && floor.length <= 2

errors.add(:floor, 'Floor is required, must be number...')
end

Other question;

When you post the form, the request goes to create action. Because of the create action, the path is redirected to http://localhost:3000/posts. When there is an error in the form, the form is re-rendered with render :new. But the url doesn't change because there is no redirect. Actually, there is no error here. This is what it should be.

How to show error message on rails views?

The key is that you are using a model form, a form that displays the attributes for an instance of an ActiveRecord model. The create action of the controller will take care of some validation (and you can add more validation).

Controller re-renders new View when model fails to save

Change your controller like below:

def new
@simulation = Simulation.new
end

def create
@simulation = Simulation.new(simulation_params)
if @simulation.save
redirect_to action: 'index'
else
render 'new'
end
end

When the model instance fails to save (@simulation.save returns false), then the new view is re-rendered.

new View displays error messages from the model that failed to save

Then within your new view, if there exists an error, you can print them all like below.

<%= form_for @simulation, as: :simulation, url: simulations_path do |f|  %>
<% if @simulation.errors.any? %>
<ul>
<% @simulation.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<div class="form-group">
<%= f.label :Row %>
<div class="row">
<div class="col-sm-2">
<%= f.text_field :row, class: 'form-control' %>
</div>
</div>
</div>
<% end %>

The important part here is that you're checking whether the model instance has any errors and then printing them out:

<% if @simulation.errors.any? %>
<%= @simulation.errors.full_messages %>
<% end %>


Related Topics



Leave a reply



Submit