17

我相信那datetime_select是黑魔法。我真正想弄清楚的是整个1i, 2i, 3i, 4i... 多个参数的东西。具体来说,它是如何在后端处理的(activerecord,其他的?)。订单号后面的“i”是什么意思?它是类型说明符吗?如果是这样,还有哪些其他可用类型?我已经阅读了 date_helper.rb 的来源,它非常不透明。

这是我的动机:

我的模型中有一个:datetime列,我想通过两个text_fields 在视图中输入:一个用于日期,一个用于时间。它们需要经过验证、合并在一起,然后存储到日期时间列中。最终,我将使用 javascript 日历将日期输入到日期字段中。

那么有人做过吗?我尝试使用虚拟属性(除了基本的 railscast 之外还没有记录),问题是当创建一个新的 activerecord 对象并具有 nil 属性时,虚拟属性失败(strftimenil 类的未定义方法,这是有道理的)。

有人有任何建议或最佳做法吗?谢谢!

4

2 回答 2

17

我有同样的问题。这是我发现的...

http://apidock.com/rails/ActiveRecord/Base/assign_multiparameter_attributes

assign_multiparameter_attributes(pairs) 私有

为需要多个构造函数参数的所有属性类实例化对象。这是通过使用这些参数在列类型或聚合类型(通过composed_of)对象上调用new 来完成的。因此,如果具有written_on(1) = "2004"、written_on(2) = "6"、written_on(3) = "24" 对,将使用 Date.new("2004"、"6 ”、“24”)。您还可以在括号中指定类型转换字符,以便在构造函数中使用参数之前对其进行类型转换。使用 i 表示 Fixnum,f 表示浮点数,s 表示字符串,a 表示数组。如果给定属性的所有值都为空,则该属性将设置为 nil。

所以这些数字是用于该列的数据类型的参数。“i”是将其转换为整数。支持其他类型,例如“f”表示浮点数等。

您可以在execute_callstack_for_multiparameter_attributes中看到它检测目标类型并实例化它并传递值。

因此,要尝试直接回答提出的问题,我认为您不能使用它来覆盖 DateTime 的创建方式,因为它使用的构造函数不支持您要传入的格式。我的解决方法是将 DateTime 列拆分为一个 Date 和一个 Time 列。然后 UI 可以按照我想要的方式工作。

我想知道是否可以在类上创建分别表示日期和时间但保留单个 DateTime 列的属性访问器。然后表单可以引用那些单独的访问器。这可能是可行的。另一种选择可能是使用composed_of进一步自定义类型。

希望对其他人有所帮助。:)

于 2010-11-23T07:40:25.933 回答
2

这就是我最终想出的。如果有人有任何意见,请告诉我。我很想得到反馈。

  validate :datetime_format_and_existence_is_valid  
  before_save :merge_and_set_datetime   

  # virtual attributes for date and time allow strings
  # representing date and time respectively to be sent
  # back to the model where they are merged and parsed
  # into a datetime object in activerecord
  def date
    if (self.datetime) then self.datetime.strftime "%Y-%m-%d"
    else @date ||= (Time.now + 2.days).strftime "%Y-%m-%d" #default
    end
  end
  def date=(date_string)
    @date = date_string.strip
  end
  def time
    if(self.datetime) then self.datetime.strftime "%l:%M %p"
    else @time ||= "7:00 PM" #default
    end
  end
  def time=(time_string)
    @time = time_string.strip
  end

  # if parsing of the merged date and time strings is
  # unsuccessful, add an error to the queue and fail
  # validation with a message
  def datetime_format_and_existence_is_valid    
    errors.add(:date, 'must be in YYYY-MM-DD format') unless
      (@date =~ /\d{4}-\d\d-\d\d/) # check the date's format
    errors.add(:time, 'must be in HH:MM format') unless # check the time's format
      (@time =~ /^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AaPp][Mm]))$|^(([01]\d|2[0-3])(:[0-5]\d){0,2})$/)
    # build the complete date + time string and parse
    @datetime_str = @date + " " + @time
    errors.add(:datetime, "doesn't exist") if 
      ((DateTime.parse(@datetime_str) rescue ArgumentError) == ArgumentError)
  end

  # callback method takes constituent strings for date and 
  # time, joins them and parses them into a datetime, then
  # writes this datetime to the object
  private
  def merge_and_set_datetime
    self.datetime = DateTime.parse(@datetime_str) if errors.empty?
  end
于 2009-10-08T14:12:00.063 回答