【问题标题】:Rails multiple fields to one model attributeRails 多个字段到一个模型属性
【发布时间】:2011-10-11 10:58:30
【问题描述】:

我到处寻找,但似乎找不到一个好的解决方案。

我的表单有一个日期(带有 datepicker 的文本字段)和一个时间(带有 timepicker 的文本字段),我想将它们映射到一个名为 due_at 的模型字段。

到目前为止,我一直在使用单独的参数在控制器中处理它,将其加入到日期时间,然后手动设置模型字段,但这很混乱,我真的认为这个逻辑应该保留在模型/视图中。

我希望能够将两个表单字段处理为模型中的一个属性,然后将其拆分为错误、编辑操作等。基本上是执行标准 datetime_select的自定义方式> 确实如此,但我会亲自动手。

我可以在我的模型中添加一些东西吗?

def due_at=(date, time)
...
end

我找了很多地方,但不知道你会怎么做。人们说要使用 javascript 来填充隐藏字段,但对于一个非常简单的问题,这似乎不是最干净的解决方案。

任何建议/帮助将不胜感激。

谢谢。

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    首先:请重命名您的字段,因为 created_at 可能会导致与 ActiveRecord 冲突。

    我对格式为 M/D/YYYY H:M(24 小时格式的小时/分钟)的字段进行了此操作

    在您的模型中:

    attr_accessor :due_date, :due_time
    
    before_validation :make_due_at
    
    
    def make_due_at
      if @due_date.present? && @due_time.present?
        self.due_at = DateTime.new(@due_date.year, @due_date.month, @due_date.day, @due_time.hour, @due_time.min)
      end
    end
    
    
    def due_date
      return @due_date if @due_date.present?
      return @due_at if @due_at.present?
      return Date.today
    end
    
    def due_time
      return @due_time if @due_time.present?
      return @due_at if @due_at.present?
      return Time.now
    end 
    
    
    def due_date=(new_date)
      @due_date = self.string_to_datetime(new_date, I18n.t('date.formats.default'))
    end
    
    
    def due_time=(new_time)
      @due_time = self.string_to_datetime(new_time, I18n.t('time.formats.time'))
    end
    
    protected
    
    def string_to_datetime(value, format)
      return value unless value.is_a?(String)
    
      begin
        DateTime.strptime(value, format)
      rescue ArgumentError
        nil
      end
    end
    

    现在在视图中:

    <%= text_field_tag :due_time, I18n.l(@mymodel.due_time, :format => :time) %>
    <%= text_field_tag :due_date, I18n.l(@mymodel.due_date, :format => :default) %>
    

    现在在 config/locales/en.yml 中(如果是英文)

      date:
        formats:
          default: "%m/%d/%Y"
      time:
        formats:
          time: "%H:%M"
    

    当然,您可以更改日期格式。

    【讨论】:

    • 当您有一个包含日期时间的文本字段时,这非常有用,但是当您有两个文本字段时,我需要一个解决方案,一个带有日期,另一个带有时间。
    • 添加两个不支持数据库的变量,确保它们进入参数并构建“真实值”并分配给“真实变量”?这是你必须添加到模型中的代码,而不是使用 Rails 魔法,但它应该可以解决问题......
    • 谢谢 jaydel,我很确定我知道你所说的使用虚拟属性是什么意思。我试图在我的例子中实现这一点,你能提供一个例子吗?
    • @Andrew Cetinick 我扩展了我的答案,希望它现在适合
    • Sled,感谢您的修改并修改您的答案。为了将due_at作为日期时间存储在数据库中,我是否应该放入before_validation回调以结合日期和时间并设置due_at?
    【解决方案2】:

    我认为date_time_attribute gem 对你来说是个不错的选择:

    class Task < ActiveRecord::Base
      include DateTimeAttribute
    
      date_time_attribute :due_at
    end
    

    它将允许您分别设置due_at_datedue_at_time

    form_for @event do |f|
      f.text_field :due_at_date
      f.text_field :due_at_time
      f.submit
    end
    
    # this will work too:
    form_for @event do |f|
      f.date_select :due_at_date
      f.time_select :due_at_time, :ignore_date => true
      f.text_field  :due_at_time_zone
      f.submit
    end
    
    # or
    form_for @event do |f|
      f.date_select :due_at_date
      f.text_field  :due_at_time
      f.submit
    end
    

    这是一个例子:

    task = Task.new
    task.due_at                      # => nil
    
    # Date set
    task.due_at_date = '2001-02-03'
    task.due_at_date                 # => 2001-02-03 00:00:00 +0700
    task.due_at_time                 # => 2001-02-03 00:00:00 +0700
    task.due_at                      # => 2001-02-03 00:00:00 +0700
    
    # Time set
    task.due_at_time = '10:00pm'
    task.due_at_time                 # => 2013-12-02 22:00:00 +0800
    task.due_at_date                 # => 2001-02-03 00:00:00 +0700
    task.due_at                      # => 2001-02-03 22:00:00 +0700
    
    # Time zone is applied as set
    task.due_at_time_zone = 'Moscow'
    task.due_at                      # => Mon, 03 Feb 2013 22:00:00 MSK +04:00
    task.due_at_time_zone = 'London'
    task.due_at                      # => Mon, 03 Feb 2013 22:00:00 GMT +00:00
    

    它还允许您使用时区、使用 Chronic 等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-20
      相关资源
      最近更新 更多