【问题标题】:Separate date and time form fields in RailsRails 中的单独日期和时间表单字段
【发布时间】:2010-09-09 14:28:34
【问题描述】:

我有一个带有日期时间列 starts_at 的 ActiveRecord 模型 Event。我想提供一个表格,其中starts_at 的日期和时间是单独选择的(例如"23-10-2010" 用于日期,"18:00" 用于时间)。这些字段应由单个列 starts_at 支持,并且验证最好也应针对 starts_at

我当然可以随意使用虚拟属性和钩子,但我想要一个更优雅的解决方案。我已经对composed_of (rdoc) 和属性装饰器 (lighthouse discussion, github) 进行了实验,但均未成功。

下面是我想要的大致轮廓..

class Event < ActiveRecord::Base
  validates_presence_of :start_date
end

# View
# On submission this should set start_date.
form_for @event do |f|
  f.text_field :starts_at_date         # date-part of start_date
  f.text_field :starts_at_time_of_day  # time-of-day-part of start_date
  f.submit
end

任何帮助表示赞赏。

【问题讨论】:

  • 我已经遇到过几次了,但仍然没有找到好的解决方案。拆分它的原因是我可以分别使用 datepicker 和 time_select。

标签: datetime forms activerecord ruby-on-rails-3


【解决方案1】:

你必须在视图中有text_field吗?

据我所知,您可以拥有一个 date_time 字段,然后只需使用两个不同的输入字段来设置字段的不同部分。

form_for @event do |f|
  f.date_select :starts_at
  f.time_select :starts_at, :ignore_date => true
  f.submit
end

由于 rails 的日期和时间选择助手设置了五个不同的参数(starts_at(1i) 用于年份部分,2i 用于月份部分,等等),这意味着 date_select 只为日期设置它们部分,而如果你将:ignore_date =&gt; true 传递给time_select,它只会设置小时和分钟部分。

如果你必须有一个text_field,我不知道该怎么做,但在发送表单之前设置日期时间参数之前,可以使用一些 jQuery 魔法。

【讨论】:

  • 很好,似乎可以工作并且是一个足够好的解决方案。但我真正想看到的是一种围绕表单助手划分和重构属性的方法。例如。 before_form_build & before_form_validation。
  • 那么我认为您需要对 params 哈希进行一些手动修改。
【解决方案2】:

今天正在为一个 Rails 项目寻找这个,并且偶然发现了这个 gem:

https://github.com/shekibobo/time_splitter

设置日期时间可能是一件困难或丑陋的事情,尤其是通过网络表单。找到一个好的 DatePicker 或 TimePicker 很容易,但让它们同时工作可能很困难。 TimeSplitter 会自动为您的日期时间或时间属性生成日期、时间、小时和分钟的访问器,从而可以轻松地使用不同的表单输入来设置日期时间字段的不同部分。

看起来它会为你完成这项工作

【讨论】:

  • 有没有办法为这个 gem 设置时区?它始终以 UTC 保存。
  • 在我的测试中,它使用的是配置的时区。你确定你设置正确吗?
  • 我尝试使用这个 gem 并立即遇到了问题stackoverflow.com/questions/29858627/…
【解决方案3】:

使用date_selecttime_select 是一个不错的方法。

但是,我想要一个text_field 作为日期(所以我可以使用 JavaScript 日期选择器)。

使用 strong_parameters 或 Rails 4+:

models/event.rb

# Add a virtual attribute
attr_accessor :start_at_date

视图/事件/_form.html.haml

- # A text field for the date, and time_select for time
= f.label :start_at
= f.text_field :start_at_date, value: (f.object.start_at.present? ? f.object.start_at.to_date : nil)
= f.time_select :start_at, :ignore_date => true

控制器/events_controller.rb

# If using a date_select, time_select, datetime_select
# Rails expects multiparameter attributes
# Convert the date to the muiltiparameter parts
def event_params
  if !!params[:event] && (params[:event]["start_at(4i)"].present? || params[:event]["start_at(5i)"].present?)

    if params[:event][:start_at_date].present?
      start_at_date = params[:event][:start_at_date]
    else
      start_at_date = Date.today
    end
    year  = start_at_date.match(/^(\d{4})[\-\/]/)[1]
    month = start_at_date.match(/[\-\/](\d{2})[\-\/]/)[1]
    day   = start_at_date.match(/[\-\/](\d{2})$/)[1]
    params[:event]["start_at(1i)"] = year
    params[:event]["start_at(2i)"] = month
    params[:event]["start_at(3i)"] = day
  end
  ...

【讨论】:

【解决方案4】:

优雅的解决方案可以提供date_time_attribute gem:

class MyModel < ActiveRecord::Base
  include DateTimeAttribute

  date_time_attribute :starts_at
end

它将允许您分别设置starts_at_datestarts_at_time

form_for @event do |f|
  f.text_field :starts_at_date
  f.text_field :starts_at_time
  f.submit
end

# this will work too:
form_for @event do |f|
  f.date_select :starts_at_date
  f.time_select :starts_at_time, :ignore_date => true
  f.text_field  :starts_at_time_zone
  f.submit
end

# or
form_for @event do |f|
  f.date_select :starts_at_date
  f.text_field  :starts_at_time
  f.submit
end

它还允许您使用时区、使用 Chronic 等。

【讨论】:

  • 你确定你可以混合date_selecttext_field吗?我无法使用 text_fieldtime_select 并且没有文档显示您可以。
  • 您不需要包含 DateTimeAttribute 模块,如 gem 存储库的 README 中所述:github.com/einzige/date_time_attribute#rails-users
【解决方案5】:

这是因为设计问题吗?如果您只是将starts_at 保存为日期时间数据类型并使用类似以下的内容,这真的会容易得多:

http://puna.net.nz/timepicker.htm#

它只是在模型的任何日期字段之上运行。

【讨论】:

  • 不,这不是设计问题。数据应该是单列,而表单构建器应该为同一列处理 2 个不同的属性。
猜你喜欢
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 2017-04-25
  • 2018-02-10
  • 1970-01-01
  • 2013-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多