Validating a time zone is valid in rails
A more lightweight and performant solution would be using TZInfo::Timezone.all_identifiers
instead of manipulating the list from ActiveSupport::TimeZone.all
.
validates :timezone, presence: true, inclusion: { in: TZInfo::Timezone.all_identifiers }
Looks like you want this:
validates_inclusion_of :timezone,
:in => ActiveSupport::TimeZone.all.map { |tz| tz.tzinfo.name }
On my machine, that list includes the following names:
...
"Europe/Istanbul",
"Europe/Kaliningrad",
"Europe/Kiev",
"Europe/Lisbon",
"Europe/Ljubljana",
"Europe/London",
...
However, a cleaner solution would be a custom validation method, like this:
validates_presence_of :timezone
validate :timezone_exists
private
def timezone_exists
return if timezone? && ActiveSupport::TimeZone[timezone].present?
errors.add(:timezone, "does not exist")
end
This is more flexible in the values it accepts:
ActiveSupport::TimeZone["London"].present? # => true
ActiveSupport::TimeZone["Europe/London"].present? # => true
ActiveSupport::TimeZone["Pluto"].present? # => false
All of the other answers are good, especially Matt Brictson's. This one works when you have someone pass something like 'Paris' to the timezone, which can be used by rails, but isn't in the list (ActiveSupport::TimeZone) that are being checked. This validation checks if it is valid for rails, and allows for 'Paris' to be valid:
validates_each :timezone do |record, attr, value|
!!DateTime.new(2000).in_time_zone(value)
rescue
record.errors.add(attr, 'was not valid, please select one from the dropdown')
end