I'm creating rails API and want to want to add validation for countries field which contains an ISO 3166-1 code on model level.
For example if use gem carmen-rails, it provides only helper country_select. Is that way to use validation for accordance country for ISO 3166-1 code in the model?
Here is the newest syntax for validation with the countries gem:
validates :country, inclusion: { in: ISO3166::Country.all.map(&:alpha2) }
You are just trying to validate that the country code entered is appropriate? this should work with carmen
validates :country, inclusion: { in: Carmen::Country.all.map(&:code) }
But if this is all you need seems like the countries gem might work well too. With countries you could do
validates :country, inclusion: { in: Country.all.map(&:pop) }
Or
validate :country_is_iso_compliant
def country_is_iso_compliant
errors.add(:country, "must be 2 characters (ISO 3166-1).") unless Country[country]
end
Update
For Region and State you can validate all 3 at the same time like this.
validates :country, :region, :state, presence: true
validate :location
def location
current_country = Country[country]
if current_country
#valid regions would be something Like "Europe" or "Americas" or "Africa" etc.
errors.add(:region, "incorrect region for country #{current_country.name}.") unless current_country.region == region
#this will work for short codes like "CA" or "01" etc.
#for named states use current_country.states.map{ |k,v| v["name"}.include?(state)
#which would work for "California" Or "Lusaka"(it's in Zambia learn something new every day)
errors.add(:state, "incorrect state for country #{current_country.name}.") unless current_country.states.keys.include?(state)
else
errors.add(:country, "must be a 2 character country representation (ISO 3166-1).")
end
end
Although Region seems unnecessary as you could imply this from the country like
before_validation {|record| record.region = Country[country].region if Country[country]}
Create a Fixture with the data provided by Wikipedia on ISO-3166-1 and validate the country based on that data.
Also you can create an auto-complete feature easing the input. You can look at the auto-complete provided here for guidance.
Related
I am using PhoneLib (https://github.com/daddyz/phonelib) to validate my phone numbers.
I have a model Subscription with a column phone_number.
I'm testing this phone number: 3052612151.
I can see that Phonelib considers it to be a valid number:
> Phonelib.valid_for_country? "3052612151", :us
#=> true
However, when I use Phonelib's validator, my record is not considered to be valid.
class Subscription < ApplicationRecord
validates :email, presence: true
validates :phone_number, phone: { countries: :us }
> s = Subscription.create(phone_number: '3052612151', email: 'example#example.com')
> s.valid?
#=> false
> s.errors.full_messages
#=> ["Phone number is invalid"]
I've been scratching my head for over an hour. Can anyone see what I've done wrong? Why does Phonelib consider the number to be valid when calling #valid_for_country? but not when used as a validator?
The only thing I can think of is maybe you should set the default country in an initializer
# config/initializers/phonelib.rb
Phonelib.default_country = "US"
Then just use validates :phone_number, phone: true in your model.
Try using countries: [:us], the validator actually does a & operation and checks if the size is greater than 0, maybe it's expecting an array. https://github.com/daddyz/phonelib/blob/master/lib/validators/phone_validator.rb#L85
The validator actually checks 4 validations, it's a really bad design that all validations return the same error message, weird :S. https://github.com/daddyz/phonelib/blob/master/lib/validators/phone_validator.rb#L63
I am trying to validate the entry a user makes in an amount field.
The field is amount_money
This field is a string which is validated on form submission
monetize :amount, :as => :amount_money
validates :amount, numericality: {only_integer: true}
validates :amount_money, numericality: {greater_than_or_equal_to: 0}
validate :amount_money_within_limit
validate :is_a_valid_number
I want to ensure there are no letters or symbols and that the amount is in an acceptable range.
the code to do this is
def amount_money_within_limit
if amount_money && amount_money.cents > 10_000_00
errors.add(:amount_money, 'cannot exceed $10,000.')
end
if amount_money && amount_money.cents < 1_00
errors.add(:amount_money, 'Problem with Amount')
end
end
this works great for input numbers, of numbers and letters, of letters, of special characters but
If I try Bob - the validation kicks in
but if I try BBob - the validation is bypassed.
If the input contains 2 Capital letters next to each other - it fails.
I've tried a downcase - but that doesn't suit as the field is monetized (money gem) - and the downcase screws up if there is valid input.
If the input to the field contains two uppercase letters - all the validations are bypassed So something like AA is not caught by any on the above validations
Why don't you use regular expressions? Something like this:
def is_a_valid_number? amount_money
amount_money =~ /\d+/
end
It seems you have put 1 validation on the wrong field, you should've put validations only on amount field (your real db field), and not on the amount_money which is automagical field from rails-money gem. I'll apply their documentation on numerical validations to your case:
monetize :amount,
:numericality => {
:only_integer => true,
:greater_than_or_equal_to => 1_00,
:less_than_or_equal_to => 10_000_00
}
You won't need any other custom validations with this setup.
Hi let's say I have the following in my accounts model:
validates :name, length: {in: 1..70, message:%Q|Please enter a decent name Sr.|}
How can I add multilingual support to those custom validation messages? I checked this tutorial
But I could not find out how to translate custom validation messages in the model.
I needed once to use translations in model so I went this way:
TITLE = { 0 => :"employee.title.mrs",
1 => :"employee.title.mr",
2 => :"employee.title.miss" }
these are options for select, and in select I used t(value_of_key_here), value was a string that was seen as a key to locale.
So in your case this might work (not really sure):
validates :name, length: {in: 1..70, message: :"enter_decent_name"}
that would return a key in your validation messages and rails will just complain about missing key in translations that you have to add into your yml file:
enter_decent_name: 'Please enter a decent name Sr.'
We are working with web development firm to build a site. We have a field where we request that the user input the amount that they would like to invest. We asked for this field to be limited to whole numbers. For example, the user should be able to invest "20" or "20.00" but not "20.50".
The developer is using Ruby ActiveRecord Validate_numericality :only_integer which is restricting the input to "20". If a user inputs and submits the value "20.00" they receive an error telling them that they need to input an integer.
Is there a way to use ActiveRecrod validate_numericality to accept only numbers that are whole numbers, not necessarily only integers? The code is currently:
validates :principal, numericality: {greater_than_or_equal_to:MINIMUM_INVESTMENT_AMOUNT,
less_than_or_equal_to:MAXIMUM_INVESTMENT_AMOUNT,
:only_integer => true}
I am hoping that there is a numericality constraint that will allow 20.00 as a whole number.
you could do this
before_validation {|a| a.principal = principal.to_i}
This will convert it to an integer without modifying the validations but if you want to notify the user that they entered something that is not a whole number then I would remove the :only_integer and create a more flexible validation like
validates :principal, numericality:{greater_than_or_equal_to:MINIMUM_INVESTMENT_AMOUNT, less_than_or_equal_to:MAXIMUM_INVESTMENT_AMOUNT}
validate :principal_is_whole_number
def principal_is_whole_number
errors.add(:principal, "must be a whole number.") unless principal.to_i == principal
end
Using Rails 3.1.3 and Ruby 1.9.3.
I want to give the user a list of possible date/time formats. The user's selection will be stored in the Users table. Date/time values are then formatted using the I18n.localize function. I actually have 10 formats; here by way of example are the first two:
config/locales/datetime.en.yml
en:
time:
format_labels:
mdyslash12: mm/dd/yyyy - hh:mm am (12-hour)
mdyslash24: mm/dd/yyyy - hh:mm (24-hour)
formats:
mdyslash12: ! '%m/%d/%Y %I:%M%p'
mdyslash24: ! '%m/%d/%Y %H:%M'
My question is where to store the list of possible date/time formats. I've identified three possibilities.
1. List options as a CONSTANT in model:
app/models/user.rb
DATETIME_FORMATS = %w[mdyslash12 mdyslash24]
validates :datetime_format, :presence => true,
:inclusion => { :in => DATETIME_FORMATS }
2. Create an application constant and validate against that:
config/initializers/constants.rb
Rails.configuration.datetime_formats = "mdyslash12 mdyslash24"
app/models/user.rb
validates :datetime_format, :presence => true,
:inclusion => { :in => Rails.application.config.datetime_formats.split(" ") }
3. Validate directly against the locale file:
app/models/user.rb
validates :datetime_format, :presence => true,
:inclusion => { :in => (I18n.t 'time.format_labels').stringify_keys.keys }
This option uses a feature that is new to me: I18n.t 'time.format_labels' returns a hash of ALL keys and values from that branch of the locale file. The hash keys are symbols, so to get a string array, I call stringify_keys to convert the symbols to strings, then keys to give me only the keys (no values).
Option #3 is the DRYest in that I don't have to list the possible values in two places. But it doesn't feel quite right to depend on the locale file for the discreet list of possible date/time formats.
What would you recommend? One of these options? Something else?
I'd go with option 1 to start with, since it's simple, clear, and fairly DRY. I might refactor to option 2 if I ended up needing that constant in another model.
Option 3 has the potential to behave differently based on the locale, so I don't like that. If you end up forgetting to specify your format labels in a new locale, your selection list might end up being empty (or if there's a typo in one locale, it might take longer to notice, since the typo would be treated as valid for that locale). Regardless it's probably a good idea to unittest this in all your supported locales.