【问题标题】:How do ruby on rails multi parameter attributes *really* work (datetime_select)ruby on rails 多参数属性如何*真正*工作(datetime_select)
【发布时间】:2010-11-30 20:58:38
【问题描述】:

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

这是我的动机:

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

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

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

【问题讨论】:

  • 在 activerecord/base.rb [assign_multiparameter_attributes] 中为需要多个构造函数参数的所有属性类实例化对象。这通过使用这些参数在列或聚合类型对象上调用 new 来工作。即:written_on(1) = "2004",written_on(2) = "6",written_on(3) = "24", 将用 Date.new("2004", "6", “24”)。您还可以在括号中指定类型转换字符,以便在构造函数中使用参数之前对其进行类型转换。使用 i 表示 Fixnum,f 表示浮点数,s 表示字符串,a 表示数组。
  • 嗨,Dean,如果您找到了自己的答案,通常的方法是“回答我自己的问题”,这样人们就可以看到问题已得到解决。
  • 不能对这个非常合理的问题给予足够的支持

标签: ruby-on-rails validation datetime multiparameter


【解决方案1】:

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

  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

【讨论】:

  • 查看 validates_timeliness 进行日期验证,更容易。另请查看 Date::DATE_FORMATS AND Time::DATE_FORMATS,以更好地创建可重复使用的更多格式。例如,我添加了 Date::DATE_FORMATS[:in_words] = "%b %e, %Y" 这样的格式,然后您可以在初始化程序中说 Date.today.to_s(:in_words)。
  • 只读取属性时不需要前缀self.*,所以最好使用"if(datetime)"...
  • @Scholle 我不同意,在与其他开发人员合作时,我想知道某些东西是属性还是私有方法。这就是我发出信号的方式......
【解决方案2】:

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

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

assign_multiparameter_attributes(pairs) 私人的

为所有属性实例化对象 需要一个以上的类 构造函数参数。这是由 在列类型上调用 new 或 聚合类型(通过composed_of) 具有这些参数的对象。所以 有对written_on(1) = “2004”,written_on(2) = “6”, written_on(3) = "24", 将实例化 written_on (日期类型)与 Date.new("2004", "6", "24")。你可以 还指定一个类型转换字符 括号有参数 在使用它们之前进行类型转换 构造函数。使用 i 表示 Fixnum,使用 f 表示 浮点数,s 代表字符串,a 代表数组。 如果给定的所有值 属性为空,该属性 将被设置为零。

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

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

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

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

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

【讨论】:

  • 是的。我将使用虚拟属性。
猜你喜欢
  • 1970-01-01
  • 2017-01-09
  • 1970-01-01
  • 1970-01-01
  • 2014-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多