“分配多参数属性的错误”日期/时间字段

时间:2013-09-17 05:46:23

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

我的应用程序有一个模型“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

2 个答案:

答案 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"

所以理论上你可以简单地加入你的字符串以获得正确的日期表示,但这不是一个好主意,因为:

  1. 这是实施细节,没有人说这个日期格式在下一个rails版本中不会改变
  2. 如果您在分配之后和保存之前尝试使用日期时间(例如,在before_save中),它将是一个字符串而不是日期时间
  3. 使用active_record datetime helpers

    由于这样做总是很痛苦,因此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