验证时区在rails中有效

Ren*_*ndy 12 ruby validation datetime ruby-on-rails ruby-on-rails-4

我在客户端使用tsjzt:http://pellepim.bitbucket.org/jstz/ 来获取我存储在用户对象中的当前用户时区.

这很好用,给了我像"欧洲/伦敦"这样的时区.我想验证何时将其传递给模型,它是一个有效的时区,因为发生了一些不好的事情.

所以我发现了这个问题:在Heroku上验证Rails应用程序的用户时区问题,并尝试了这个验证:

validates_inclusion_of :timezone, :in => { in: ActiveSupport::TimeZone.zones_map(&:name) }
Run Code Online (Sandbox Code Playgroud)

但是名称与tzinfo不同.我认为我的客户端检测到时区字符串"Europe/London"本质上是TimeZone类中TimeZone映射的值组件而不是名称 - 在本例中将设置为"London".

所以我尝试了这个:

validates_inclusion_of :timezone, :in => { in: ActiveSupport::TimeZone.zones_map(&:tzinfo) }
Run Code Online (Sandbox Code Playgroud)

对于另一个SO问题或我改变的问题的原始答案:tzinfo都没有工作,因为他们都失败验证时:时区是"欧洲/伦敦",显然这是一个有效的时区!

我对这个时区验证做错了什么,我该如何解决?

Mat*_*son 18

看起来你想要这个:

validates_inclusion_of :timezone,
                       :in => ActiveSupport::TimeZone.all.map { |tz| tz.tzinfo.name }
Run Code Online (Sandbox Code Playgroud)

在我的机器上,该列表包含以下名称:

...
"Europe/Istanbul",
"Europe/Kaliningrad",
"Europe/Kiev",
"Europe/Lisbon",
"Europe/Ljubljana",
"Europe/London",
...
Run Code Online (Sandbox Code Playgroud)

但是,更清洁的解决方案是自定义验证方法,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

这在它接受的值中更灵活:

ActiveSupport::TimeZone["London"].present? # => true
ActiveSupport::TimeZone["Europe/London"].present? # => true
ActiveSupport::TimeZone["Pluto"].present? # => false
Run Code Online (Sandbox Code Playgroud)


Jia*_*ang 5

一个更轻量级和高性能的解决方案是使用TZInfo::Timezone.all_identifiers而不是从ActiveSupport::TimeZone.all.

validates :timezone, presence: true, inclusion: { in: TZInfo::Timezone.all_identifiers }
Run Code Online (Sandbox Code Playgroud)