In a Rails model, if I have a field that is for proper names, what is the best practice way to ensure they are uniformly capitalized despite potentially lazy input from users?
IE let's say the model is Contact
and the field is Name
. No matter what the user inputs I want the words to be capitalized, ie the model would tranform the following input to the following output:
john doe -> John Doe
j doe -> J Doe
John doe -> John Doe
john doe jr -> John Doe Jr
So, do you create a before_save
callback and tranform the field with a regex, or do you create some kind of validation, or something different? I'd very much appreciate answers with an emphasis on the rationale, of why you would do it one way or another, because that's what I'm most stuck on.
The method you want is titleize
. The capitalize
method only does the first character in the entire string so "john doe".capitalize #=> "John doe"
, "john doe".titleize #=> "John Doe"
.
As for how to implement it, you could go with a before_save
, but I like to do these type of simple preparations of single attributes with pseudo-attributes. Basically, you define a writer
method for an attribute that will hide the default one created by ActiveRecord
. You'll still be able to access the attribute using the write_attribute
method (docs). Doing it this way will ensure that the attribute is set properly as soon as you assign it, meaning that even before you save it, you can be sure your object is in a valid state:
class Contact < ActiveRecord::Base
def name=(s)
write_attribute(:name, s.to_s.titleize) # The to_s is in case you get nil/non-string
end
end
I would suggest to use before_save .
like in you model :
before_save :capitalize_name
def capitalize_name
self.name = self.name.split.collect(&:capitalize).join(' ') if self.name && !self.name.blank?
end
A cleaner rendition of @tserif's is the following:
def name=(s)
super s.titleize
end
This removes the dependency on write_attribute
and the need to specify the attribute name name
in favor of a more primitive method. I don't see the need for to_s
, unless you want the ability to assign a symbol.
The most important question is how will you be displaying the names? If it will be on the web, as I would guess, I wouldn't handle this in the model at all. The simplest solution is to just use css text-tansform: capitalize;
to handle the capitalization, but if you'll be displaying it often you would want to define a decorator or helper method to normalize it for you.
def full_name
[first_name, last_name].map { |name| name[0].upcase + name[1..-1] }.join(' ')
end
Note that instead of mapping capitalize
you would just want to uppercase the first letter. Somebody named RJ or CJ would probably want the J to remain capitalized.
The data is canonical regardless, seeing the parts capitalized is purely display.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With