【问题标题】:Save one date into two datetime columns将一个日期保存到两个日期时间列中
【发布时间】:2015-08-12 12:42:18
【问题描述】:

我的计划模型中有两个日期时间列:starts_atends_at

要求:创建/更新计划时,用户将看到:

  • 1 选择菜单用于选择日期
  • 1 选择菜单用于选择开始时间(小时:分钟)
  • 1 选择菜单用于选择结束时间(小时:分钟)

我想让用户从单个选择菜单中选择日期。然后将日期保存在两个日期时间列中。我只希望日期相同,而不是时间。

我当前的代码让用户在两个日期时间属性上都输入日期,这很麻烦:

<%= f.label :starts_at %>
<%= f.datetime_select :starts_at %>

<%= f.label :ends_at %>
<%= f.datetime_select :ends_at %>

我试过了:

# view
<%= f.date_select :starts_at, order: [:day, :month, :year] %>
<%= f.time_select :starts_at, ignore_date: true %>
<%= f.time_select :ends_at %>

# controller
def update
  @partner  = Partner.find(params[:partner_id])
  @schedule = @partner.schedules.find(params[:id])
  @klass    = Klass.find(schedule_params[:klass_id])
  @schedule.activity_id = @klass.activity_id

  date = Date.civil(schedule_params["starts_at(1i)"].to_i, schedule_params["starts_at(2i)"].to_i, schedule_params["starts_at(3i)"].to_i)
  @schedule.ends_at = date

  @schedule.update(schedule_params)
end

private

  def schedule_params
    params.require(:schedule).permit(:klass_id, :starts_at, :ends_at, :quantity)
  end

但它不起作用。

【问题讨论】:

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


    【解决方案1】:

    我认为您实际上缺少参数,因为它不在表单中。

    视图不应该是这样的吗?

    <%= f.date_select :starts_at, order: [:day, :month, :year] %>
    <%= f.time_select :starts_at, ignore_date: true %>
    <%= f.date_select :ends_at, order: [:day, :month, :year] %>
    <%= f.time_select :ends_at, ignore_date: true %>
    

    【讨论】:

    • 但如果我这样做,那么日期将有 2 个选择输入。我只想要一个。
    【解决方案2】:

    我无法发表评论,因为我没有足够的声望点,但以下方法不起作用吗?

    @schedule.ends_at = @schedule.starts_at
    

    【讨论】:

    • 这将使开始时间和结束时间相同。
    • @i.am.noob ...这就是你所说的你想要的:“我想让用户从一个选择菜单中选择日期。然后将日期保存在这两个日期时间中列。”您缺少的是您希望日期相同而不是时间相同的部分。
    • @DaveNewton 但是这个会覆盖ends_at列上的时间。
    • @i.am.noob 所以只问用户一次时间,两次日期。
    • @DaveNewton 不,我希望用户输入时间表的一个日期,然后输入不同的开始时间和结束时间。
    【解决方案3】:

    您也可以尝试在@schedule.starts_at 上使用the Rails DateTime change method 来设置:ends_at 值的时间。

    喜欢:

    @schedule.ends_at = @schedule.starts_at.change(
      hour: schedule_params[:ends_at].hour, 
      min: schedule_params[:ends_at].min, 
      sec: 0
    )
    

    或者类似的东西......

    【讨论】:

      【解决方案4】:

      我明白了。但是代码很丑。

      def update
        @partner  = Partner.find(params[:partner_id])
        @schedule = @partner.schedules.find(params[:id])
        @klass    = Klass.find(schedule_params[:klass_id])
      
        @schedule.city_id     = @partner.city_id
        @schedule.activity_id = @klass.activity_id
        @schedule.klass_id    = schedule_params[:klass_id]
        @schedule.quantity    = schedule_params[:quantity]
      
        @schedule.starts_at = DateTime.civil(
          schedule_params["starts_at(1i)"].to_i, schedule_params["starts_at(2i)"].to_i,
          schedule_params["starts_at(3i)"].to_i,
          schedule_params["starts_at(4i)"].to_i, schedule_params["starts_at(5i)"].to_i
        )
      
        @schedule.ends_at = DateTime.civil(
          schedule_params["starts_at(1i)"].to_i, schedule_params["starts_at(2i)"].to_i,
          schedule_params["starts_at(3i)"].to_i,
          schedule_params["ends_at(4i)"].to_i, schedule_params["ends_at(5i)"].to_i
        )
      
        @schedule.save
      end
      
      private
      
      def schedule_params
        params.require(:schedule).permit(:klass_id, :starts_at, :ends_at, :quantity)
      end
      

      我仍然欢迎任何能想出更好答案的人。

      【讨论】: