【问题标题】:Validating a time zone is valid in rails验证时区在 rails 中有效
【发布时间】:2015-10-25 20:31:52
【问题描述】:

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

这很好用,给了我像“欧洲/伦敦”这样的时区。我想验证何时将其传递到模型中,以防发生不好的事情。

所以我发现了这个问题:Issue validating user time zone for Rails app on Heroku 并尝试了这个验证:

validates_inclusion_of :timezone, :in => { in: ActiveSupport::TimeZone.zones_map(&:name) }

但是名称与 tzinfo 不同。我认为我的客户端检测到的时区字符串“Europe/London”本质上是 TimeZone 类中 TimeZone 映射的值组件,而不是名称 - 在这种情况下将设置为“London”。

所以我尝试了这个:

validates_inclusion_of :timezone, :in => { in: ActiveSupport::TimeZone.zones_map(&:tzinfo) }

另一个 SO 问题的原始答案或我用:tzinfo 更改的答案都不起作用,因为当 :timezone 是“欧洲/伦敦”时,它们都无法通过验证,而这显然是一个有效的时区!

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

【问题讨论】:

  • It doesn't look like "Europe/London" 在该映射类中得到明确支持。然而,伦敦
  • 如果您查看 ActiveSupport::TimeZone.zones_map 的输出,您会看到包含“Europe/London”的输出 - 这就是我想将我输入的字段与...进行比较的...我只是不知道怎么样!

标签: ruby-on-rails ruby validation datetime ruby-on-rails-4


【解决方案1】:

看起来你想要这个:

validates_inclusion_of :timezone,
                       :in => ActiveSupport::TimeZone.all.map { |tz| tz.tzinfo.name }

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

...
"Europe/Istanbul",
"Europe/Kaliningrad",
"Europe/Kiev",
"Europe/Lisbon",
"Europe/Ljubljana",
"Europe/London",
...

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

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

这在接受的值上更加灵活:

ActiveSupport::TimeZone["London"].present? # => true
ActiveSupport::TimeZone["Europe/London"].present? # => true
ActiveSupport::TimeZone["Pluto"].present? # => false

【讨论】:

  • 第一个建议不起作用,因为它似乎有语法错误:语法错误,意外'}',期待=>
  • 第二个建议确实有效 - 但我很想看到第一个有效!
  • @RenegadeAndy 我已经修复了语法错误。好收获!
  • 很好 - 它在不应该被阻止的时候被阻止了?
  • 我没有仔细看就从你的问题中复制并粘贴了。周围的{ } 用于哈希文字或块,在这种情况下都不适用,所以我删除了它们。
【解决方案2】:

更轻量级和高性能的解决方案是使用TZInfo::Timezone.all_identifiers,而不是从ActiveSupport::TimeZone.all 操作列表。

validates :timezone, presence: true, inclusion: { in: TZInfo::Timezone.all_identifiers }

【讨论】:

  • 我们使用并存储了时区的唯一名称,所以我改用了ActiveSupport::TimeZone.all.map( &:name )
【解决方案3】:

所有其他答案都很好,尤其是 Matt Brictson 的。当您有人将诸如“巴黎”之类的内容传递到时区时,此方法有效,该时区可以由 rails 使用,但不在正在检查的列表 (ActiveSupport::TimeZone) 中。此验证检查它是否对 rails 有效,并允许 'Paris' 有效:

  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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    相关资源
    最近更新 更多