Error messages in nested attribute - ruby-on-rails

I've three models called Account,User and AccountPermission.
I'm creating the Account via AccountPermission while creating user.
However, If a problem occurs related with Account :name, the system throws something like that below.
Account permissions account name has already been taken
So, I just need to fix this error message.
I've tried to add a message attribute to my validation. It is just appending to actual message.
I've also tried locale thing. Still just appending
en:
activerecord:
errors:
models:
account:
attributes:
name:
taken: 'bla bla'
As far as I see in ActiveModel. This message's structure comes from below
locale/en.yml in ActiveModel
en:
errors:
format: "%{attribute} %{message}"
So, Is there any way edit this message painless ? If I even delete the model name, It's enough.

Error message is concatenated from the error itself and the attribute name, which is account_permissions/account.name in the provided error.
You can add locale for your attribute names like so:
en:
activerecord:
attributes:
account: # this is model name
name: "Name"
or
en:
activerecord:
attributes:
account_permissions/account:
name: "Account name"

Related

Overwrite rails error message format only for custom error messages

Is there a way to overwrite the message format only for custom error messages?
I know that it is possible to overwrite rails error message formats at the attribute and model level by using
en:
errors:
format: '%{message}'
or
en:
activemodel:
errors:
models:
person:
format: '%{message}'
or
en:
activemodel:
errors:
models:
person:
attributes:
name:
format: '%{message}'
source (https://github.com/rails/rails/pull/32956).
The issue with this approach, no matter which level the format is overwritten at, this always overwrites the format for all default rails error messages.
If I have a model Person with an attribute name and I add a en.yml config like
en:
activemodel:
errors:
models:
person:
attributes:
name:
older_than_eighteen: "You must be older than eighteen"
format: '%{message}'
this now leads to all error message for the name attribute of person being interpolated without the attribute name. If I got some validate :name, presence: true the error message for a blank name becomes can't be blank instead of Name can't be blank.
I know that I could add another error message to the en.yml file above like blank: "Name can't be blank" but I would like to avoid that and instead only change the format for my custom error message.
Is there a way to achieve this?
add into your config/application.rb
config.active_model.i18n_customize_full_message = true
According to the RoR official docs:
Controls whether the Error#full_message format can be overridden in an i18n locale file. Defaults to false.
When set to true, full_message will look for a format at the attribute and model level of the locale files. The default format is "%{attribute} %{message}", where attribute is the name of the attribute, and message is the validation-specific message. The following example overrides the format for all Person attributes, as well as the format for a specific Person attribute (age).

Overwrite Rails validation message

How do you overwrite a validation message in Rails?
Even if I pass in a proc like so..
validates :my_item, uniqueness: {
scope: [:name, :type],
message: -> (object, data) do
"This item is already taken"
end,
}
It still appends the [object] to the front of the message. So that is reads: "[name of the object] This item is already taken"
Edit:
Also have tried adding a ^ to the beginning of message. Still does not work.
"^This item is already taken"
Instead of trying to override it at the model level, just leverage the fact that you're essentially trying to tweak the en locale.
In config/locales/en.yml you should be able to do something like this:
en:
activerecord:
errors:
messages:
taken: "This item is already taken."
models:
my_item:
taken: "This item is already taken."
I haven't tested this config directly, but the messages key should change the message for all models. Otherwise you can specify the message on a per-model basis. I don't believe that this will include the object name. You can find a list of the field names in the Rails Internationalization Guide.

ActiveRecord Validations : String added to error message in locales

I'm trying customize validation error messages using i18n.
Let's say I have an Address model that validates the presence of a zip_code.
My config/locales/activerecord.fr.yml looks like this
fr:
activerecord:
errors:
models:
address:
attributes:
civility:
blank: "Some message"
The issue if I fail the validation, the error message I'l have in #address.errors.full_messages will be:
"Zip code Some message"
Why does Zip code gets added to my error message ? And how can I avoid this behaviour ?
You can just add:
errors:
format: "%{message}"
This way you will just show error message with out attribute name.
Edit: this should be added to config/locales/fr.yml and not config/locales/activerecord.fr.yml (which also has errors:)
Found a gem which will solve your purpose
With the help of this gem, 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
You could simply use:
#address.errors.messages[:zip_code] # or #address.errors[:zip_code]
#=> ['Some message']

Translate Rails model association - not working

Anyone has some tips as how to translate model associations in Rails?
For example: I have a Person model, which can have many Phone. However, a Person needs to have at least one Phone. I'm not able to translate that validation. The best I could do was this:
validates_presence_of :phones, :message => "At least one phone is required."
And on my YAML, I replaced this line to omit the %{attribute}:
format: ! '%{message}'
This way only my message is displayed, and I avoid the un-translated field name to be displayed.
This is causing me a lot of headache, because some gems simply don't allow me to pass :message => "something describing the error", so I wanted to configure all the error messages through my YAML.
Also, with some models I'm able to translate their attributes, while with others I'm not. For example:
activerecord:
attributes:
additional_info:
account_manager: "Manager"
This works. I can see on my form "Manager". However, when this field has an error, Rails will display it as "Additional info account manager can't be blank".
I tried this:
activerecord:
errors:
models:
additional_info:
attributes:
account_manager: "Manager"
But no luck.
I did read the docs, but no clue on why it's happening.
Here are the valid key paths for Rails 4.1:
# Basic Attribute on Model
activerecord:
attributes:
#{model_class.model_name.i18n_key}:
#{attribute_name}:
"Localized Value"
# Attribute on Nested Model
activerecord:
attributes:
#{model_class.model_name.i18n_key}/#{association_name}:
#{attribute_name}:
"Localized Value"
#{association_name}:
#{attribute_name}:
"Fallback Localized Value"
So, given this model (which has the i18n_key of :person):
class Person
has_many :friends
end
You'd have these locale definitions:
activerecord:
attributes:
person:
first_name:
"My Name"
person/friends:
first_name:
"My Friend's Name"
friends:
first_name:
"A Friend's Name"
If your model is a namespace, such as:
class MyApp::Person
has_many :friends
end
the i18n_key becomes :my_app/person and your / key starts to wear out:
activerecord:
attributes:
my_app/person:
first_name:
"My Name"
my_app/person/friends:
first_name:
"My Friend's Name"
friends:
first_name:
"A Friend's Name"
Rails 3.2 has changed this behavior. The way I've posted before is deprecated.
Now, in order to translate associations, there is the need to add a slash (instead of nesting everything). So instead of this:
activerecord:
attributes:
person:
additional_info:
account_manager: "Manager"
The correct now is:
activerecord:
attributes:
person:
additional_info/account_manager: "Manager"
Also, I figured out that has_many associations are being translated differently from that. If you want to translate those, the following example may help:
activerecord:
attributes:
emails:
address: "E-mail field"
Instead of the model name, like I did above, you need to pass the association name, in this case emails.
Check this comment and pull request for more info:
https://github.com/rails/rails/commit/c19bd4f88ea5cf56b2bc8ac0b97f59c5c89dbff7#commitcomment-619858
https://github.com/rails/rails/pull/3859

Rails 3 Customer Error message

I'm trying to do something very simple. I have a validates presence of in rails 3:
validates_presence_of [:first_nm]
When this fires, it gives the following crappy message:
"first nm cannot be blank"
I want to override the error message to give a friendly field name for "first nm"
"Please fill out your First Name"
I have seen all kinds of plugins, localization, humanized attributes tutorials, but these don't seem to work or are outdated. Is there no simple way to do this in Rails 3?
For localization, i've tried this:
# Sample localization file for English. Add more files in this directory for other locales.
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
activerecord:
errors:
messages:
taken: "has already been taken"
record_invalid: "Validation failed: %{errors}"
models:
customer:
blank: "This is a custom blank message for %{model}: %{attribute}"
attributes:
first_nm:
blank: "This is a custom blank message for first name"
Alas, no luck. My error message did not change.
On thing that might be related. I'm not inheriting from ActiveRecord, because this object is getting saved via soap, not database. Instead, I have the following:
class Customer
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
end
Have you seen this page on ActiveRecord localization? It seems to be for Rails 3. I can't test it right now, but by the document it seems you can do:
models.user.attributes.first_nm.blank = "Please fill out your First Name"

Resources