我的应用程序有一个模型“Appointments”,它有一个start和end属性,都是日期时间。我试图将日期和时间部分与我的表单分开设置,以便我可以使用单独的日期和时间选择器。我以为我应该能够这样做。从我读到的内容中,rails应该将这两个部分组合在一起,然后将组合字段解析为日常时间,就像通常那样 我得到的错误:
2 error(s) on assignment of multiparameter attributes [error on assignment ["2013-09-16", "15:30"] to start (Missing Parameter - start(3)),error on assignment ["2013-09-16", "16:30"] to end (Missing Parameter - end(3))]
这些是请求参数:
{"utf8"=>"✓", "authenticity_token"=>"OtFaIqpHQFnnphmBmDAcannq5Q9GizwqvvwyJffG6Nk=", "appointment"=>{"patient_id"=>"1", "provider_id"=>"1", "start(1s)"=>"2013-09-16", "start(2s)"=>"15:30", "end(1s)"=>"2013-09-16", "end(2s)"=>"16:30", "status"=>"Confirmed"}, "commit"=>"Create Appointment", "action"=>"create", "controller"=>"appointments"}
我的模特
class Appointment < ActiveRecord::Base
belongs_to :patient
belongs_to :practice
belongs_to :provider
validates_associated :patient, :practice, :provider
end
观点的相关部分:(简单形式)
<%= f.input :"start(1s)", :as => :string, :input_html => { :class => 'date_time_picker' , :value => Date.parse(params[:start]) }%>
<%= f.input :"start(2s)", :as => :string, :input_html => { :class => 'date_time_picker' , :value => Time.parse(params[:start]).strftime('%R') }%>
<%= f.input :"end(1s)", :as => :string, :input_html => { :class => 'date_time_picker' , :value => Date.parse(params[:end]) }%>
<%= f.input :"end(2s)", :as => :string, :input_html => { :class => 'date_time_picker' , :value => Time.parse(params[:end]).strftime('%R') }%>
更新: 现在是我的模型看起来如何,我一直在尝试使用getter / setter方法,但我被卡住了因为start-dat,start_time等在模型中是nil而且参数不是通过
发送的class Appointment < ActiveRecord::Base
belongs_to :patient
belongs_to :practice
belongs_to :provider
validates_associated :patient, :practice, :provider
before_validation :make_start, :make_end
############ Getter Methods for start/end date/time
def start_time
return start.strftime("%X") if start
end
def end_time
return self.end.strftime("%X") if self.end
end
def start_date
return start.strftime("%x") if start
end
def end_date
return self.end.strftime("%x") if self.end
end
def start_time=(time)
end
def end_time=(time)
end
def start_date=(date)
end
def end_date=(date)
end
def make_start
if defined?(start_date)
self.start = DateTime.parse( self.start_date + " " + self.start_time)
end
end
def make_end
if defined?(end_date)
self.start = DateTime.parse( end_date + " " + end_time)
end
end
end
答案 0 :(得分:2)
您是否试图模仿#date_select
?如果是,请参阅答案的第二部分。
如果要将DateTime分配给数据库,则必须是DateTime对象。在这里,您使用字符串数组["2013-09-16", "15:30"]
。
您可以使用regexps轻松地从这些字符串计算日期时间:
/(?<year>\d+)-(?<month>\d+)-(?<day>\d+)/ =~ params[ 'start(1s)' ]
/(?<hours>\d+):(?<minutes>\d+)/ =~ params[ 'start(2s)' ]
datetime = DateTime.new( year.to_i, month.to_i, day.to_i, hours.to_i, minutes.to_i )
这将在本地变量中存储年,月,日,小时和分钟,并根据它创建新的数据时间,然后您可以将其分配给模型。
然而,数据库无法按原样存储ruby DateTime实例,因此在保存日期或日期时间字段以将其转换为字符串时,rails会进行转换。使用的方法是#to_s(:db)
,例如:
DateTime.now.to_s(:db) # => "2013-09-17 09:41:04"
Time.now.to_date.to_s(:db) # => "2013-09-17"
所以理论上你可以简单地加入你的字符串以获得正确的日期表示,但这不是一个好主意,因为:
由于这样做总是很痛苦,因此rails可以帮助创建和使用日期时间表单输入。
FormBuilder#datetime_select
将仅采用您想要的属性并构建所有需要的输入:
<%= f.datetime_select :start %>
这实际上会创建5个输入,分别命名为“start(1i)”(年),“start(2i)”(月),“start(3i)”(day),“start(4i)”(小时) )和“start(5i)”(分钟)。
如果感觉熟悉,那是因为这是我们在本答案的第一部分中建立日期时间时检索到的确切数据。当您使用这些精确键为数据时间字段分配哈希时,它将使用它们的值构建日期时间对象,就像我们在第一部分中所做的那样。
您自己的代码中的问题是您刚刚提供了“start(1i)”和“start(2i)”。 Rails不明白,因为你只传递了年份和月份,比计算日期时间要少得多。
答案 1 :(得分:0)
请参阅How do ruby on rails multi parameter attributes *really* work (datetime_select)
根据这个问题,多参数属性方法适用于Date
但不适用于DateTime
个对象。对于Date
,您可以将年,月和日作为单独的值传递,因此Missing Parameter - start(3)
,因为预期的第三个参数不存在。
DateTime
至少需要五个参数进行实例化DateTime.new(2013, 09, 16, 15, 30)
,因此您不能依赖自动解析。您必须首先拆分params,在这种情况下,您可以在使用before_filter或类似方法保存对象之前自己轻松解析它。
参见构造函数: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/DateTime.html#method-c-new
和多参数说明: http://apidock.com/rails/ActiveRecord/AttributeAssignment/assign_multiparameter_attributes