How do you internationalize the message being thrown - ruby-on-rails

class Foo < ActiveRecord::Base
...
validates_presence_of :name, :message => "cannot be blank.
...
I am looking for ways to internationalize the message so that a localized message is shown from users from a different locale. How should I do that?

Rails Guides: Translations for active records will give you a hint about it. Basically, you don't have to store the string in your model. You can change it in your locale files.

I18n is one of the good way to internationalize the message.
But if your message customization level is too much then every time you need to modify the ymls and also need to add new yml for different set of users.
In such case you can use 'redis' it gives you more dynamic control. It store data in key => value hash. It is really fast. Following links will help youl
http://redis.io/documentation
http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html
https://github.com/jodosha/redis-store
http://www.engineyard.com/blog/2009/key-value-stores-for-ruby-part-4-to-redis-or-not-to-redis/

Related

Model named "Type" in Rails

Good Day.
I have a problem with my Model named "Type". The error is:
undefined method `all' for ActiveRecord::AttributeMethods::Serialization::Type:Class
In this particular part of validation:
validates :type_id, presence: { message: 'selected is invalid' }, inclusion: { in: 1..Type.all.count }
Maybe it's due to reserved names conflict in Rails. But is there a way that Rails will consider this name before I proceed to refactor? (if nothing else to do).
It's really a bad choice for a name but it's too late.
PS.
When I do 'Type.all.count' in rails console, there are no errors that occured.
Here is a list of reserved words in Rails. As you can see, type has also been reported to cause problems.
Rails is built over convention over configuration agreement, so I would suggest just to pick another model name (which is not mentioned in stated blog post).
Take a look at this thread to get an idea of what should be done to turn your Type model to something else.
In case you are completely sure model name is not the case, you could try to trick around with different validation notations like
inclusion: { in: 1.upto(Type.all.count).to_a}
Ruby's constant lookup is resulting in it finding the "wrong" Type class. Using "::Type" forces ruby to use the top level Type constant.
You should note that this count will be done once only: when the rails instance starts. If new types were to be added, the validation would not take that into account. If a type were ever deleted then it would not allow the last type to be used.
If you have a type association then you could do
validates_presence_of :type
Upon saving it would try and load the corresponding Type object from the database, so saving would fail if there was no such row.
For a really strong guarantee, you could use a foreign key constraint (the foreigner gem adds helpers to rails migrations for this, but you can also just write the sql statement by hand)
Fortunately, I found a workaround. However, it is not recommended but if you don't want to do Migration and ton's of Refractions, here is my solution (credits to twonegatives).
in my validation code:
inclusion: { in: 1.upto(:type_alias) }
then create that method type_alias
def type_alias
Type.all.count
end

How do I specify column name and types while extending ActiveRecord::Base in Ruby on Rails?

Forgive my ignorance if I am missing something really trivial, I am very new to RoR.
Coming from Django background I remember models being like
class Post(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
both column name and field type are clearly specified.
Where as, when I write this rails command
> rails g model Post title:string description:text
all I get is
class Post < ActiveRecord::Base
attr_accessible :description, :title
end
Is there a way to write column names and field types while extending ActiveRecord::Base instead of having them only in the migration file?
Thanks, any help is appreciated
attr_accessible is deprecated and strong params replaces it functionality in the controller.
If you want to get a list of the schema information in your model file you can annotate it at the top of the file. This was best practices at some point, however I do not think it is used as much. I personally do not like this and just use the schema.
Post on best practices and annotating:
http://rails-bestpractices.com/posts/68-annotate-your-models
Gem to auto annotate:
https://github.com/ctran/annotate_models
The most wonderful thing about ActiveRecord is that you don't need to do any mapping, as all the fields are being automatically mapped using current schema. Of course default mapping can be overridden if needed, however this is a very rare case.
This approach is called "convention over configuration" and is present all over Rails - it assumes most common parameters for what you are trying to achieve so it saves a lot of unnecessary coding and mapping. It might feel weird at start, especially that you'll need to learn how to override those defaults, but I promise you are gonna love it when you get used to it. :)

How to access translation key for ActiveModel validation error?

I Have a situation, where I wan't to store the translation key for a validation error in my db instead of the error message it self. Imagine the following situation:
class Car < ActiveRecord::Base
validates_presence_of :year, :fuel
end
car = Car.new(:fuel => 'Diesel')
car.save!
#=> ActiveRecord::RecordInvalid
Now if I call:
car.errors
#=> :year=>["can't be blank"]
I get the translated error message.
Instead I would like to extract the translation key that would generate this (in this case I think it would be something like errors.messages.blank), so I can store it in my database in a different model e.g. FailedCar so I can later on generate an I18n customized form for filling in the missing information manually in a view.
UPDATE
I think it's this method that I need to hook into. I want to fetch the key and the options returned, so I can perform the translations again at a later point in time.
Okay I finally got it!
The solution is NOT to patch or do anything on the rails side of things - instead - the answer lies in the I18n gem.
I18n, which rails uses for translations by standard, has the ability to plugin new backends to provide more flexibility to it. In this case, the backend called metadata does exactly what I needed. When adding I18n::Backend::Simple.include(I18n::Backend::Metadata) to an initializer, it gives me the possibility of extracting all translation related information directly from the error message string by adding the method call translation_metadata.
A fantastic simple solution to a complicated problem :-)
Have you looked at (.yml) local files too? You can store it as a translation string. For more Info Rails Internationalization.

Rails Best Practice for User-Configurable Global Attribute "Defaults"

Sorry about the awkward phrasing of the title -- not quite sure of the best way to title this but here's what I'm seeing assistance with:
In a Rails app, let's say we've got a model for a Product, and one of the attributes of the product is Price.
On the admin side of my app, I'd like to be able to set a "default" price that could be referred to if any new Product created isn't assigned a Price. If a Product does have a value for Price, then it would be used.
This is, of course, an example -- and I ask this question because I've got to imagine this is a common pattern. This can be applied to any resource that might have user-configurable global defaults or resource-specific values.
In pure Ruby, this would be solved, I think, with a class variable, so I'd be able to define ##default_price within the Product class and be able to refer to Product.default_price if the instantiated object's value doesn't exist.
My research here has pointed me towards the rails-settings-cached gem, which would allow for something like MyApp.default_price, but I'm wondering if there's a more elegant (non-plugin) way to accomplish this within the base Rails framework.
Note I'd like to setup this structure in code, but I want to be able to define the actual values through my app (i.e. config files aren't the solution I'm looking for).
Can someone enlighten me with the Rails way of handling this?
ActiveRecord picks up default attribute values from the database schema. However, these are baked into the migration and table schema and not configurable.
If you want configurability, the pattern that I've used is a before_validation callback method to set a value if the attribute is blank, e.g.:
class Product < ActiveRecord::Base
before_validation :set_price_if_blank
validates :price, :presence => true # sanity check in case the default is missing
has_one :price
private
def set_price_if_blank
self.price = Price.default if self.price.blank?
end
end
class Price < ActiveRecord::Base
def self.default
##default ||= Price.where(:default => true).first
end
end
This assumes that your price table is populated with a row that has a default flag. You could achieve this, e.g. through a seeds.rb file. I've added a validation rule to make sure that you still get an error if no default exists. It adds robustness to your application.
Also note that it's best to use Integers or Decimals for price data, not floats. See this answer.

what is the right way to model status values as an association in Rails?

I have a model called Contacts.
Contacts can have different status "bad, positive, wrong..."
These status may need to be changed over time, but across all contacts, they are the same options.
Should I model it this way:
Contacts.rb
belongs_to :status_contact
StatusContacts.rb
has_many :contacts
Then I manually populate the types of status in the table?
I then want to use Ajax to click a button corresponding to a value to update the value for Contacts.
It looks like you're trying to ensure that the values for your status are always going to restricted to a set of possible answers of your choosing. If that's all you're trying to do, there's no special need for a separate table. You can use the magic of ActiveRecord validations instead here.
First, create a string database column for Contact called :status.
Then you can use a validation to ensure that the values are limited to the ones you want. In Rails 3, you can do it like this:
validate :status, :inclusion => { :in => %w( bad positive wrong ) }
(If you're using Rails 2, use #validates_inclusion_of instead.)
In ActiveRecord, validations check that the object's values are valid before saving; it refuses to persist the object into the database until all validations pass.
Your naming strikes me as a little weird—ContactStatus sounds a little nicer to me—but I see this as being the general idea to achieve what you want.
No clear answer yet --- I think I need to use the table because it would allow the users to add and modify the types of status used across their application.

Resources