Using Rails I'm trying to get an error message like "The song field can't be empty" on save. Doing the following:
validates_presence_of :song_rep_xyz, :message => "can't be empty"
... only displays "Song Rep XYW can't be empty", which is not good because the title of the field is not user friendly. How can I change the title of the field itself ? I could change the actual name of the field in the database, but I have multiple "song" fields and I do need to have specific field names.
I don't want to hack around rails' validation process and I feel there should be a way of fixing that.
Now, the accepted way to set the humanized names and custom error messages is to use locales.
# config/locales/en.yml
en:
activerecord:
attributes:
user:
email: "E-mail address"
errors:
models:
user:
attributes:
email:
blank: "is required"
Now the humanized name and the presence validation message for the "email" attribute have been changed.
Validation messages can be set for a specific model+attribute, model, attribute, or globally.
In your model:
validates_presence_of :address1, message: 'Put some address please'
In your view
<% m.errors.each do |attr, msg| %>
<%= msg %>
<% end %>
If you do instead
<%= attr %> <%= msg %>
you get this error message with the attribute name
address1 Put some address please
if you want to get the error message for one single attribute
<%= #model.errors[:address1] %>
Try this.
class User < ActiveRecord::Base
validate do |user|
user.errors.add_to_base("Country can't be blank") if user.country_iso.blank?
end
end
I found this here.
Update for Rails 3 to 6:
validate do |user|
user.errors.add(:base, "Country can't be blank") if user.country_iso.blank?
end
Here is another way to do it.
What you do is define a human_attribute_name method on the model class. The method is passed the column name as a string and returns the string to use in validation messages.
class User < ActiveRecord::Base
HUMANIZED_ATTRIBUTES = {
:email => "E-mail address"
}
def self.human_attribute_name(attr)
HUMANIZED_ATTRIBUTES[attr.to_sym] || super
end
end
The above code is from here
Yes, there's a way to do this without the plugin!
But it is not as clean and elegant as using the mentioned plugin. Here it is.
Assuming it's Rails 3 (I don't know if it's different in previous versions),
keep this in your model:
validates_presence_of :song_rep_xyz, :message => "can't be empty"
and in the view, instead of leaving
#instance.errors.full_messages
as it would be when we use the scaffold generator, put:
#instance.errors.first[1]
And you will get just the message you specified in the model, without the attribute name.
Explanation:
#returns an hash of messages, one element foreach field error, in this particular case would be just one element in the hash:
#instance.errors # => {:song_rep_xyz=>"can't be empty"}
#this returns the first element of the hash as an array like [:key,"value"]
#instance.errors.first # => [:song_rep_xyz, "can't be empty"]
#by doing the following, you are telling ruby to take just the second element of that array, which is the message.
#instance.errors.first[1]
So far we are just displaying only one message, always for the first error. If you wanna display all errors you can loop in the hash and show the values.
Hope that helped.
Rails3 Code with fully localized messages:
In the model user.rb define the validation
validates :email, :presence => true
In config/locales/en.yml
en:
activerecord:
models:
user: "Customer"
attributes:
user:
email: "Email address"
errors:
models:
user:
attributes:
email:
blank: "cannot be empty"
In the custom validation method use:
errors.add(:base, "Custom error message")
as add_to_base has been deprecated.
errors.add_to_base("Custom error message")
Related to the accepted answer and another answer down the list:
I'm confirming that nanamkim's fork of custom-err-msg works with Rails 5, and with the locale setup.
You just need to start the locale message with a caret and it shouldn't display the attribute name in the message.
A model defined as:
class Item < ApplicationRecord
validates :name, presence: true
end
with the following en.yml:
en:
activerecord:
errors:
models:
item:
attributes:
name:
blank: "^You can't create an item without a name."
item.errors.full_messages will display:
You can't create an item without a name
instead of the usual Name You can't create an item without a name
One solution might be to change the i18n default error format:
en:
errors:
format: "%{message}"
Default is format: %{attribute} %{message}
I recommend installing the custom_error_message gem (or as a plugin) originally written by David Easley
It lets you do stuff like:
validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"
Here is another way:
If you use this template:
<% if #thing.errors.any? %>
<ul>
<% #thing.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
You can write you own custom message like this:
class Thing < ActiveRecord::Base
validate :custom_validation_method_with_message
def custom_validation_method_with_message
if some_model_attribute.blank?
errors.add(:_, "My custom message")
end
end
This way, because of the underscore, the full message becomes " My custom message", but the extra space in the beginning is unnoticeable. If you really don't want that extra space at the beginning just add the .lstrip method.
<% if #thing.errors.any? %>
<ul>
<% #thing.errors.full_messages.each do |message| %>
<li><%= message.lstrip %></li>
<% end %>
</ul>
<% end %>
The String.lstrip method will get rid of the extra space created by ':_' and will leave any other error messages unchanged.
Or even better, use the first word of your custom message as the key:
def custom_validation_method_with_message
if some_model_attribute.blank?
errors.add(:my, "custom message")
end
end
Now the full message will be "My custom message" with no extra space.
If you want the full message to start with a word capitalized like "URL can't be blank" it cannot be done. Instead try adding some other word as the key:
def custom_validation_method_with_message
if some_model_attribute.blank?
errors.add(:the, "URL can't be blank")
end
end
Now the full message will be "The URL can't be blank"
Just do it the normal way:
validates_presence_of :email, :message => "Email is required."
But display it like this instead
<% if #user.errors.any? %>
<% #user.errors.messages.each do |message| %>
<div class="message"><%= message.last.last.html_safe %></div>
<% end %>
<% end %>
Returns
"Email is required."
The localization method is definitely the "proper" way to do this, but if you're doing a little, non-global project and want to just get going fast - this is definitely easier than file hopping.
I like it for the ability to put the field name somewhere other than the beginning of the string:
validates_uniqueness_of :email, :message => "There is already an account with that email."
Here is my code that can be useful for you in case you still need it:
My model:
validates :director, acceptance: {message: "^Please confirm that you are a director of the company."}, on: :create, if: :is_director?
Then I have created a helper to show messages:
module ErrorHelper
def error_messages!
return "" unless error_messages?
messages = resource.errors.full_messages.map { |msg|
if msg.present? && !msg.index("^").nil?
content_tag(:p, msg.slice((msg.index("^")+1)..-1))
else
content_tag(:p, msg)
end
}.join
html = <<-HTML
<div class="general-error alert show">
#{messages}
</div>
HTML
html.html_safe
end
def error_messages?
!resource.errors.empty?
end
end
If you want to list them all in a nice list but without using the cruddy non human friendly name, you can do this...
object.errors.each do |attr,message|
puts "<li>"+message+"</li>"
end
In your view
object.errors.each do |attr,msg|
if msg.is_a? String
if attr == :base
content_tag :li, msg
elsif msg[0] == "^"
content_tag :li, msg[1..-1]
else
content_tag :li, "#{object.class.human_attribute_name(attr)} #{msg}"
end
end
end
When you want to override the error message without the attribute name, simply prepend the message with ^ like so:
validates :last_name,
uniqueness: {
scope: [:first_name, :course_id, :user_id],
case_sensitive: false,
message: "^This student has already been registered."
}
I tried following, worked for me :)
1 job.rb
class Job < ApplicationRecord
validates :description, presence: true
validates :title,
:presence => true,
:length => { :minimum => 5, :message => "Must be at least 5 characters"}
end
2 jobs_controller.rb
def create
#job = Job.create(job_params)
if #job.valid?
redirect_to jobs_path
else
render new_job_path
end
end
3 _form.html.erb
<%= form_for #job do |f| %>
<% if #job.errors.any? %>
<h2>Errors</h2>
<ul>
<% #job.errors.full_messages.each do |message|%>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :description %>
<%= f.text_area :description, size: '60x6' %>
</div>
<div>
<%= f.submit %>
</div>
<% end %>
A unique approach I haven't seen anyone mention!
The only way I was able to get all the customisation I wanted was to use an after_validation callback to allow me to manipulate the error message.
Allow the validation message to be created as normal, you don't need to try and change it in the validation helper.
create an after_validation callback that will replace that validation message in the back-end before it gets to the view.
In the after_validation method you can do anything you want with the validation message, just like a normal string! You can even use dynamic values and insert them into the validation message.
#this could be any validation
validates_presence_of :song_rep_xyz, :message => "whatever you want - who cares - we will replace you later"
after_validation :replace_validation_message
def replace_validation_message
custom_value = #any value you would like
errors.messages[:name_of_the_attribute] = ["^This is the replacement message where
you can now add your own dynamic values!!! #{custom_value}"]
end
The after_validation method will have far greater scope than the built in rails validation helper, so you will be able to access the object you are validating like you are trying to do with object.file_name. Which does not work in the validation helper where you are trying to call it.
Note: we use the ^ to get rid of the attribute name at the beginning of the validation as #Rystraum pointed out referencing this gem
graywh's answer is the best if it actually locales different in displaying the field name. In the case of a dynamic field name (based on other fields to display), I would do something like this
<% object.errors.each do |attr, msg| %>
<li>
<% case attr.to_sym %>
<% when :song_rep_xyz %>
<%= #display error how you want here %>
<% else %>
<%= object.errors.full_message(attr, msg) %>
<% end %>
</li>
<% end %>
the full_message method on the else is what rails use inside of full_messages method, so it will give out the normal Rails errors for other cases (Rails 3.2 and up)
Upgraded #Federico answer to be universal for all field errors.
In your controller.rb:
flash[:alert] = #model.errors.messages.values
# [["field1_err1", "field1_err2"], ["field2_err1"], ["field3_err1"]]
messages method "returns a Hash of attributes with an array of their error messages" as in rails docs.
Then, to display those errors in a form:
<% flash.each do |type, type_arr| %>
<% type_arr.each do |msg| %>
<ul>
<li>
<%= msg.to_sentence %>
</li>
</ul>
<% end %>
<% end %>
Related
Here's what happens in my app:
customer enters phone number
phone number is searched in customer model to see if it exists
if it does exist, go to the customer show page
if it does not exist, go to customer new page to create new customer
According to my understanding, model validations are for data that is entered/edited/deleted into the database.
However, how can we check (use the validation) before anything searches in the database? And if it is incorrect (example: using letters instead of digits for phone number), then would show the error.
I was implementing html form input options to prevent someone from inputting letters in the phone number input box like this:
<%= form_tag(new_customer_path, method: :get) do %>
<%= telephone_field_tag :phone, nil, placeholder: "Phone Number", required: true, pattern: "[0-9]{10}", title: "Number must be 10 digits", maxlength: "10", class: "input-lg" %>
<%= submit_tag "Enter", class: "btn btn-primary btn-lg" %>
<% end %>
However my form was getting big because I would then put the html form input box options on everything (phone, zip-code, email, ect.).
What is more proper "Rails" way? Using active record validations to show errors, or providing html form input options to validate the data beforehand? Or is it the combination of both (max secure? client side and before database)?
Model
class Customer < ActiveRecord::Base
validates_presence_of :first_name, :last_name, :phone, :email, :zip_code
validates_uniqueness_of :phone, :email
validates :phone, :zip_code, :numericality => {:only_integer => true}
validates_length_of :phone, is: 10
validates_length_of :zip_code, is: 5
end
Controller
def new
if #customer = Customer.find_by(phone: params[:phone])
flash[:success] = "Welcome back"
redirect_to #customer
else
#customer = Customer.new(phone: params[:phone])
flash.now[:warning] = "Customer not found, please sign up!"
end
end
error messages partial
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %>">
×
<ul>
<li>
<p><%= value %></p>
</li>
</ul>
</div>
<% end %>
The rails validation is probably good enough but if you're worried about it you could add a javascript validation on the client side. There are several plugins you could use if you want to do form validations client side or you could write your own. This might be helpful: http://www.tutorialspoint.com/javascript/javascript_form_validations.htm
Just add front end validations with JavaScript and HTML. Your Rails validations looks fine.
Html: required attribute.
Jquery: Check out this link - http://jqueryvalidation.org/
Ruby on Rails 4.1
The form has validations checked in the model. I have custom messages that are showing the attribute name before the message.
I am trying to specify the translation of the attribute in the en.yml file OR just remove the attribute name. I am not getting an error but it is only humanizing the attributes without a custom message.
Example, one message I get is * Cc name your name on the credit card cannot be blank, I want it to say Your name on the credit card cannot be blank OR Credit card name cannot be blank.
Model:
class Payment < ActiveRecord::Base
validates_presence_of :telephone, :email, :address1, :city, :state, :postal_code, :country, :cc_type, :cc_number, :ccv, :expires_on, :ship_name, :ship_address1, :ship_city, :ship_state, :ship_postal_code, :ship_country
validates_presence_of :cc_name,
:message => ' Your name on the credit card cannot be blank'
validates_presence_of :name_auth,
:message => ' Your name authorizing the purchase cannot be blank'
The error message file:
<% if #payment.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(#payment.errors.count, "error") %>
</div>
<ul>
<% #payment.errors.full_messages.each do |msg| %>
<li>* <%= msg.humanize %></li>
<% end %>
</ul>
</div>
<% end %>
The en.yml file:
en:
activerecord:
attributes:
cc_name: "Credit card name"
name_auth: "Authorizing name"
date_auth: "Authorized date"
card_holder_auth: "Authorized card holder"
charge_auth: "Authorizing payment"
cc_number: "Credit card number"
ccv: "Card code verification (CCV)"
So after way too much time I figured out that the best answer should be to set the format of the errors. Who wants the attribute name in the error? I could easily add it, and who actually names their attributes what thay want the end use to see? Anyway this re-formats the error messages:
en:
errors:
format: "%{message}"
The default is "%{attribute} %{message}", which IMO is normally not wanted and should be changed.
It would be better to put the error message into en.yml as follows:
en:
activerecord:
errors:
models:
payment:
attributes:
cc_name:
blank: "Credit card name cannot be blank"
Then you can remove the custom message in the model.
I am experimenting with a simple people/new page to practice showing error messages. Right now, with the below set-up, the error messages display okay but look a little awkward because the text says "Firstname can't be blank", "Lastname can't be blank" and so forth. Basically I want the text to say "First Name can't be blank" and "Last Name can't be blank" (with spaces), but I'm assuming the error messages are just following the attribute names I defined in the Model, and there's really no way to change those explicitly.
So how can I change that? Can I not achieve that change without making changes to this particular partial? (shared_error_messages)
Thanks,
Screenshot of the new view below.
people_controller.rb
class PeopleController < ApplicationController
def new
#person = Person.new
#people = Person.all
end
def create
#person = Person.new(person_params)
if #person.save
redirect_to new_person_path
else
render 'new'
end
end
private
def person_params
params.require(:person).permit(:firstname, :lastname, :age)
end
end
person.rb
class Person < ActiveRecord::Base
validates :firstname, presence: true, length: {maximum: 15}, format: { with: /\A[a-zA-Z]+\z/,
message: "only allows letters" }
validates :lastname, presence: true, length: {maximum: 15}, format: { with: /\A[a-zA-Z]+\z/,
message: "only allows letters" }
validates :age, presence: true, length: {maximum: 3}
end
new.html.erb
Enter your information
<hr>
<%= form_for #person do |f| %>
<%= render 'shared/error_messages', object: f.object %>
First Name: <%= f.text_field :firstname %><br>
Last Name: <%= f.text_field :lastname %><br>
Age: <%= f.number_field :age %><br>
<%= f.submit "See Your Life Clock" %>
<% end %>
shared/_error_messages
<% if object.errors.any? %>
<div id="error_explain">
<h2><%= pluralize(object.errors.count, "error") %> prohibited this from being saved to DB</h2>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Assuming you're using Rails 3.2 or later, the "best" way to do this is with localization. Edit your en.yml file and add this:
en:
activerecord:
attributes:
person:
firstname: "First Name"
lastname: "Last Name"
The error reporting system will look up human-friendly names for your attributes from the localization file. Thie may seem heavy-handed, but in my opinion it is the best way because these names will be accessible anywhere, centralized, and easy to maintain.
If you need the friendly name in your own code, (for example, in a label on an edit form or a column header in a list table) you can access it like this:
Person.human_attribute_name(:firstname)
Now if you change the en.yml, the change will reflect throughout your site. And should you ever need to localize to another language, you're on the right track already.
If this is too much for you, you can change your validations to have complete sentences for their messages, and then change your _error_messages partial to look like this:
<% if object.errors.any? %>
<div id="error_explain">
<h2><%= pluralize(object.errors.count, "error") %> prohibited this from being saved to DB</h2>
<ul>
<% object.errors.each do |attr, msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
An old question, but may be someone facing the same problem benefit from it, so I'm answering it.
In the view you used something like First Name: <%= f.text_field :firstname %> better to use something as follows which will give you good field names by default in your situation.
<%= f.label :firstname, 'First Name' %><br>
<%= f.text_field :firstname %>
I have already done some research but didn't managed to find how to localize the attributes for my form object.
Here is the relevant part of my form object model:
class Pledge
include ActiveModel::Validations
include ActiveModel::Conversion
include ActiveAttr::Attributes
extend ActiveModel::Naming
attribute :pledge_amount
attribute :reward_id
attribute :message
validates :message, presence: true, length: { maximum: 140 }
validates :reward_id, presence: true
validates :pledge_amount, presence: true
...
end
And my locale file, pledges/en.yml:
en:
activerecord:
models:
pledge: "Pledge"
attributes:
pledge:
pledge_amount: "Pledge Amount"
reward_id: "Reward"
message: "Message"
helpers:
submit:
pledge:
create: "Next Step"
label:
pledge:
pledge_amount: "Enter your pledge amount"
reward_id: "Select your reward"
message: "Write a Support Message"
With this setup I managed to localize successfully the labels on the form, heres a part of the form code:
<%= form_for #pledge do |f| %>
<% if #pledge.errors.any? %>
<div id="error_explanation">
<h2><%= t :not_saved, count: #pledge.errors.count, model: t(:pledge) %></h2>
<ul>
<% #pledge.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
...
<%= f.label :pledge_amount %>
<%= f.text_field :pledge_amount %>
...
<%= f.submit class: "btn btn-lg btn-primary" %>
<% end %>
This renders the :pledge_amount label like: "Enter your pledge amount" in English, and the :submit button as "Next Step", great.
The problem happens when validations fail and I render the form with errors with the code I have under the tag, witch gives me the errors existent in the model but with blank attribute names, like this:
one error prohibited this Pledge from being saved:
- can't be blank
When it was supposed to render:
one error prohibited this Pledge from being saved:
- Pledge Amount can't be blank
If you are curious about this message in particular here's the code for that, shortened:
errors/en.yml
en:
not_saved:
one: "one error prohibited this %{model} from being saved:"
other: "%{count} errors prohibited this %{model} from being saved:"
errors:
format: "%{message}"
activerecord:
errors:
messages:
blank: "%{attribute} can't be blank"
This works for all of my other models, but for this one for some reason it doesn't work, I think I'm using the wrong key on my pledges/en.yml file, as my Pledge model doesn't inherit from ActiveRecord...
Someone know the proper key to achieve this?
Put the translations on activemodel instead of activerecord in your yaml:
en:
activemodel:
models:
pledge: "Pledge"
attributes:
pledge:
pledge_amount: "Pledge Amount"
reward_id: "Reward"
message: "Message"
I dug this answer up from comments in an old RailsCast. See comment from Greg Yardley.
I managed to partially resolve this by adding custom messages on each validation I have in my form object, like this:
validates :pledge_amount, :presence => { :message => I18n.t(:blank_pledge_amount) }
And my en.yml file
blank_pledge_amount: "Please insert a pledge amount"
This way it works fine, but I would still like to know a better solution if someone has a better one.
I hope this helps others with the same problem.
In order to validate the presence and the length of the message attribute, both with their messages I did like this:
validates_presence_of :message, :message => I18n.t(:blank_message)
validates_length_of :message, :maximum => 140, message: I18n.t(:message_too_long)
I know I can fix this issue with i18n, which I will try to do if I have the time, but for a quicker fix I was curious: Is there a way to add the attribute name to a rails validation error? For example, I have the following in my model:
validates_presence_of :name
The validation error rendered is can't be blank. I'd prefer it to say Name can't be blank.
validates_presence_of :name, :format => { :message => "whatever you want" }
Use errors.full_messages:
<ul>
<% #record.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
Only -
validates_presence_of :name, :message => "Name can't be blank"
for validates_presence_of , error-locale is - "can't be blank"; attribute/property name is prefixed during validation. You can override this by above.
So, for your case, since property name is 'Name', error will automatically become "Name can't be blank".
To override the property name for all validation, you can use human_attribute_name(http://apidock.com/rails/ActiveModel/Translation/human_attribute_name)