在Rails中单独的日期和时间表单字段

时间:2010-09-09 14:28:34

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

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

我当然可以使用虚拟属性和钩子,但我想要一个更优雅的解决方案。我已尝试使用composed_ofrdoc)和属性装饰器(lighthouse discussiongithub),但未成功。

以下是我想要的大致概述..

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

任何帮助表示感谢。

5 个答案:

答案 0 :(得分:39)

您是否必须在视图中使用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 => true传递给time_select,则只会设置小时和分钟部分。

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

答案 1 :(得分:9)

今天正在关注Rails项目,并遇到了这个宝石:

https://github.com/shekibobo/time_splitter

  

设置DateTimes可能是一件困难或丑陋的事情,尤其是通过网络表单。找到一个好的DatePicker或TimePicker很容易,但让它们在两者上工作可能很困难。 TimeSplitter会自动为日期时间或时间属性生成日期,时间,小时和分钟的访问器,这使得使用不同的表单输入来设置日期时间字段的不同部分变得微不足道。

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

答案 2 :(得分:3)

使用date_selecttime_select是一种不错的方式。

但是,我希望日期为text_field(因此我可以使用JavaScript日期选择器)。

使用strong_parameters或Rails 4 +:

模型/ 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
  ...

答案 3 :(得分:2)

优雅的解决方案可能会提供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

它还允许您使用时区,使用慢性等。

答案 4 :(得分:0)

这是因为设计问题吗?如果您将starts_at保存为日期时间数据类型并使用类似:

,则会更容易

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

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