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
How to Call a Controller'S Method from a View (As We Call from Helper Ideally)
Is There an Inverse 'Member' Method in Ruby
Rails Object Relationships and Json Rendering
Cannot Use Rvm-Installed Ruby With Sudo
Rails: Skinny Controller Vs. Fat Model, or Should I Make My Controller Anorexic
How to Create a Private Class Method
How to Find a Min/Max with Ruby
Cron Job Not Working in Whenever Gem
How to Swap Keys and Values in a Hash
Dynamic Class Definition with a Class Name
"Rake Assets:Precompile" Gives Punc Error
Bundler Not Working with Rbenv, Could Not Find [Gem]
Rails 3. Creating a Production Database
How to Implement a Friendship Model in Rails 3 for a Social Networking Application
How Does One Use Rescue in Ruby Without the Begin and End Block