Override nested attributes name using I18n - ruby-on-rails

I have two models Store and StoreDetail as the following:
class Store
has_one :store_detail, dependent: :destroy
end
And StoreDetail:
class StoreDetail
belongs_to :store, class_name: 'Store'
belongs_to :state, class_name: 'State'
belongs_to :city, class_name: 'City'
belongs_to :zip_code, class_name: 'Zip Code'
end
And I override the attribute of state as the following:
attributes:
store/store_detail:
state: "State"
city: "City"
zip_code: "Zip Code"
But I got the validation messages:
Store detail state can't be blank
Store detail city can't be blank
Store detail zip code can't be blank
I want to make it without "Store detail", as the following:
State can't be blank
How can I override nested attributes ?

This is very possible with i18n:
en:
activerecord:
errors:
models:
store_detail:
attributes:
state:
blank: State can't be blank.
city:
blank: City can't be blank.
zip_code:
blank: Zip code cant't be blank.
Very important
All of those nested labels starting with "en" and ending with "models" must be exactly as they are specified in the example.
It is essential for the model name in the en.yml (or whichever kangage file you are using)
Model name must match model.rb because this identifies the field names to be validated for activerecord
The validation field names must match your schema.rb field names, like zip_code, not zip.
The "blank:" identifier tells Rails activerecord component to do a string replace what you have in the i18n yaml file when that particular validation fails.
Debugging i18n (added)
Validate the YAML: If you don't see the en.yml validation message you defined, but the default keeps showing, your en.yml is not functioning for some reason. YAML is very picky about spaces in the file and any trailing spaces in the file, etc. But it does not show any errors, it just reverts to using Rails default messages. Here's one YAML Lint tool: http://yaml-online-parser.appspot.com/
Rails spec for i18n: http://guides.rubyonrails.org/i18n.html.
Debug i18n: Use the gem i18n-tasks to create a comprehnsive report of the your i18n components : https://github.com/glebm/i18n-tasks
Application.rb: Make sure you have i18n setup.
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
config.i18n.default_locale = :en
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
If you want custom error messages for activerecord type errors, you have to work through i18n. It isn't a tidy thing. It's not at all DRY, but it is what's available.

You can use custom validation messages:
class StoreDetail < ActiveRecord::Base
validates :state_id, presence: true,
message: I18n.t(:state_cant_be_blank)
end
And then in locales/*.yml
en:
state_cant_be_blank: State can't be blank

Related

How do I exclude a field from the search filter in Rails Admin?

When I search for a user with 'test', it gives me a Postgres error because category is an integer.
Started GET "/admin/user?model_name=user&utf8=%E2%9C%93&query=test" for ::1 at 2020-02-21 17:43:44 -0500
Processing by RailsAdmin::MainController#index as HTML
Parameters: {"model_name"=>"user", "utf8"=>"√", "query"=>"test"}
ActiveRecord::StatementInvalid - PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: "test"
LINE 1: ...users.name ILIKE '%test%') OR (users.category IN ('test')) O...
I don't have category as a configured field for the model.
class User < ApplicationRecord
include RailsAdminUser
module RailsAdminUser
extend ActiveSupport::Concern
included do
rails_admin do
list do
fields :id, :email, :name, :company, :sign_in_count, :current_sign_in_at, :current_sign_in_ip
end
I can't find how to exclude category from the fields that it wants to search. I'm OK with leaving that field out of the search. It seems to construct a query with every single field. I tried to hide the category field but that didn't work.
list do
configure :category do
hide
end
Fields docs: https://github.com/sferik/rails_admin/wiki/Fields
Full docs: https://github.com/sferik/rails_admin/wiki
rails_admin 1.4.2
I tried
list do
field :category do
visible false
filterable false
end
But it didn't work.
A previous developer had
config\initializers\rails_admin_reload.rb
Rails.application.config.to_prepare do
RailsAdmin::ApplicationController.class_eval do
before_action :reload_rails_admin, if: Rails.env.development? # Reloading RailsAdmin Config Automatically
def reload_rails_admin
RailsAdmin::Config.reset
load("#{Rails.root}/config/initializers/rails_admin.rb")
I added
class User < ApplicationRecord
rails_admin do
xxx
end
And
module RailsAdminUser
extend ActiveSupport::Concern
included do
rails_admin do
xxx
Which were not even throwing errors, so it was not even reading those files or methods. I assume they wanted to reload the Rails Admin configuration whenever it changed, but it seems to also discard any and all model configurations too! I commented out the before_action and it worked.
I also added
list do
field :category do
visible false
searchable false
end
Rails Admin seems to cache the configuration for models so whenever you change the configuration (like searchable true => false) you have to restart the server. Very annoying.

Localisation of attributes in Rails virtual models

I've created a virtual (non-persistent) model in Rails 3 (see below)
I now need to apply translations to the model but the standard translations locations don't seem to work. e.g.
en:
activerecord:
attributes:
media_upload:
title: "My Title"
I know I can apply this directly to the label with an optional string parameter eg. f.label :title, t('activerecord.attributes.media_upload') but that doesn't work for error messages resulting from validations. Similarly, I could add a key to the translations file for the label helper as suggested in Localise nested virtual attribute in Rails but this also fails to work for the validations.
helpers:
label:
media_upload:
title: "My Title"
Apart from redefining all of the relevant validation messages, is there any other way I can do localisation of attributes in non-persistent models??
A sample model is shown below,
class MediaUpload
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :media_file, :title
validates_presence_of :media_file
validates_presence_of :title
def initialize(attributes = {})
unless attributes.nil?
attributes.each do |name, value|
send("#{name}=", value)
end
end
end
def persisted?
false
end
end
You need write like this:
en:
activemodel:
attributes:
media_upload:
title: "My Title"
not activerecord replace it with activemodel
It seems like you are using simple_form gem for generation of forms.
So following i18n chapter from github your internationalization file should look like this
en:
simple_form:
labels:
media_upload:
media_file: My File
title: My Title
If you are using Rails 4 than there is an easier way to make ActiveModel Form Objects. You can just include ActiveModel::Model like so
class MediaUpload
include ActiveModel::Model
attr_accessor :media_file, :title
validates_presence_of :media_file
validates_presence_of :title
end

Rails - Customize model validation error messages but without a database

I have a model that validates a form but it does not inherit from ActiveRecord....it does not have a database
I am validating certain fields in the model but i want to have custom validation messages.....in the past I've went into the
en.yml
en:
activerecord:
models:
mymodel: "CHANGE TO SOMETHING ELSE"
and could easily change it to whatever i want but it is not working for this model....i think its because its not inheriting from ActiveRecord.....
how can i customize my validation errors?
try including translations like this:
include ActiveModel::Translation
EDIT:
if your model had an email attribute and the blank validation didnt pass you can format you locale like this
locale:
en:
activemodel:
attributes:
mymodel:
email: "foo"
errors:
models:
mymodel:
blank: "bar"
here are other errors you can add a locale
https://github.com/rails/rails/blob/3-2-stable/activemodel/lib/active_model/locale/en.yml
You want to use ActiveModel support for validations, as added in Rails 3.
class MyModel
include ActiveModel::Validations
attr_accessor :name
validates :name, presence: true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
end
Please see these references:
http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/
http://www.rubyinside.com/rails-3-0s-activemodel-how-to-give-ruby-classes-some-activerecord-magic-2937.html
The first link even includes use of an i18n file for errors, as you referenced.

Inheriting Rails i18n validation error messages in the subclass

What I understand
Suppose I have a class with a handy validation like:
User < ActiveRecord::Base
validates :username, :format => {/regex/}, :message => :name_format
end
In this case, I can use i18n to make the error message translatable, by including the following in my /config/locals/en.yml:
en:
activerecord:
errors:
models:
user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
This is fine and generally really handy.
What I want to know:
My question is: What happens when I have subclasses that inherit from User:
UserSubclassOne < User
# extra stuff
end
UserSubclassTwo < User
# extra stuff
end
...
UserSubclassEnn < User
# extra stuff
end
Now the problem is that Rails can't find the translation user_subclass_one.attributes.username.name_format.
It complains:
translation missing:
en.activerecord.errors.models.user_subclass_one.attributes.username.name_format
I'd hope that Rails would look up the hierarchy of UserSubclassOne to User when searching for a string in en.yml and then notice when it gets a 'hit', but (unless I've done something horribly wrong) apparently that doesn't happen.
An obvious solution is to duplicate the data in en.yml.en.errors.models for user, user_subclass_one, user_subclass_two, etc, but my Rails-sense tells me that this is deeply wrong.
Any ideas, folks?
Potential Complication:
User is defined in a gem MyGem that is included in a Rails engine MyEngine that is included in the full-on Rails app MyApp that defines UserSubclassOne, ..., UserSubclassEnn. I don't think this should matter though, since the validations are running in MyGem::User, which is where the en.yml file lives -- just wanted to let people know in case it does.
Ultimate problem/solution:
So it turns out that the problem was namespacing. Recall that MyApp (which defines UserSubclassOne) uses MyGem (which defines User). It turns out User is actually in the namespace MyGem (this is not necessarily always the case), so the full declaration line at the beginning of User is not:
User < ActiveRecord::Base
but rather
MyGem::User < ActiveRecord::Base
.
When the i18n gem looks up the class hierarchy, it notices this namespace and searches for my_gem/user, rather than simply user, my_gem.user, my_gem: user, etc.
Thus I had to change my en.yml file to:
/config/locals/en.yml:
en:
activerecord:
errors:
models:
my_gem/user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
and bingo!
So it turns out that the problem was namespacing. Recall that MyApp (which defines UserSubclassOne) uses MyGem (which defines User). It turns out User is actually in the namespace MyGem (this is not necessarily always the case), so the full declaration line at the beginning of User is not:
User < ActiveRecord::Base
but rather
MyGem::User < ActiveRecord::Base
.
When the i18n gem looks up the class hierarchy, it notices this namespace and searches for my_gem/user, rather than simply user, my_gem.user, my_gem: user, etc.
Thus I had to change my en.yml file to:
/config/locals/en.yml:
en:
activerecord:
errors:
models:
my_gem/user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
and bingo!
According to the Rails Guides for i18n regarding Error Message Scopes (5.1.1) for Active Record validation error messages, what you're attempting to do should work:
Consider a User model with a validation for the name attribute like this:
class User < ActiveRecord::Base
validates :name, :presence => true
end
<...snip...>
When your models are additionally using inheritance then the messages are looked up in the inheritance chain.
For example, you might have an Admin model inheriting from User:
class Admin < User
validates :name, :presence => true
end
Then Active Record will look for messages in this order:
activerecord.errors.models.admin.attributes.name.blank
activerecord.errors.models.admin.blank
activerecord.errors.models.user.attributes.name.blank
activerecord.errors.models.user.blank
activerecord.errors.messages.blank
errors.attributes.name.blank
errors.messages.blank
This way you can provide special translations for various error messages at different points in your models inheritance chain and in the attributes, models, or default scopes.
So, in your case, assuming your classes look something like this:
app/models/user.rb
User < ActiveRecord::Base
validates :username, :format => {/regex/}, :message => :name_format
end
app/models/user_subclass.rb
UserSubclass < User
validates :username, :format => {/regex/}, :message => :name_format
end
and your config/locales/en.yml looks something like:
en:
activerecord:
errors:
models:
user:
attributes:
username:
name_format: 'has the way-wrong format, bro!'
then the message searching for a validation on UserSubClass should go:
activerecord.errors.models.user_sublcass.attributes.username.name_format # fail
activerecord.errors.models.user_sublcass.name_format # fail
activerecord.errors.models.user.attributes.username.name_format # success
activerecord.errors.models.user.name_format
# ...
Assuming that your model files and yaml files look similar to what's above, then the potential complication you mentioned may be the issue, but obviously I can't be certain.

Adding translations for the models in the Rails application

I am new to ROR. I am trying add translations to my application. I have added translations for the controllers.
Where to add translations for models as i am not having any /config/locales -> models folder ->en.yml file .
In the model i am having lines like
validates_presence_of :name, :message => "Name cannot be blank!"
If i want to add translations for the message "Name cannot be blank", shall i put directly as like
validates_presence_of :name, :message => I18n.t(str_name_notblank)
Please give suggestions
To add translations to your models you just need to put them under activerecord->models and activerecord->attributes. Here's an example in polish:
pl:
activerecord:
models:
patient: "Pacjent"
attributes:
patient:
first_name: "Imię"
last_name: "Nazwisko"
address: "Ulica"
postal_code: "Kod"
city: "Miejscowość"
Note that the attributes element is not under the patient element, but actually includes it again. I found this after some debugging and it actually worked for me. The Rails I18n guide suggested a different structure, but it didn't work.
The best way to translate standard Rails messages (like the ones for validation) is to download the correct translation file from Sven Fuchs' Rails Locale Data Repository (rails-18n) and put it into your config/locales folder (you can change the name). Then you'd remove your :message string and just use the standard messages, but translated to your liking.

Resources