在 rails 中以单一形式更新来自 table 的多条记录?

Update multiple records from a table in a single form in rails?

我有一个包含 72 个时间段的页面,每个时间段旁边都有一个单选按钮,表示可用/不可用。

我希望医生能够 select 无论他们是否有空,然后在完成后单击“更新”。

这意味着表单必须接受所有 72 条记录。

我(认为)我可以通过一些非常底层的编程来解决这个问题。但是我不知道 'rails way' 是什么?

到目前为止我所知道的

我试过的

如果这个想法不好(很可能是这样),请不要使用它。但我的想法是首先生成接下来 3 天内所有可能的时间

time_now = Time.now 
current_time =  time_now 
three_days = time_now + 3.days

hours = []
(current_time.beginning_of_hour.to_datetime.to_i .. three_days.beginning_of_hour.to_datetime.to_i).step(1.hour) do |date|
hours << Time.at(date)
end

    @hours = hours

然后,使用这些开始时间作为散列中的键,假设 available: false 作为散列中的值(除非 Availability.where(user: current_user).all 另有说明),并将其传递给视图以设置默认值单选按钮的位置,然后医生可以根据需要更新单选按钮并在完成后提交。

问题是

i) 我不知道这是否是一种 good/bad/ugly 方法 ii)(主要问题)我将如何为散列中的每个 key/value 对创建一个带有单选按钮的表单? (一个提交按钮)

注意:到目前为止,我在 rails 中知道的唯一形式是通过 form_for,但我热衷于使用这种形式的最佳实践

这个没有'rails way'。 Rails 在很多方面都自以为是。但是,不是这样。

在我看来,您的问题至少有两个部分。首先是构建合适的数据结构。我认为您可以通过以下方式清理现有代码:

time_now = Time.now
start_time = time_now.beginning_of_hour.to_datetime.to_i
end_time = (time_now + 3.hours).beginning_of_hour.to_datetime.to_i

@hours = (start_time..end_time).step(1.hour).map {|t| Time.at(t)}

...这主要是装饰性的。 (请注意,我使用 3.hours 而不是 3.days 只是为了使输出更短。)它为您节省了一些作业并使用 .map 而不是整个推送到 array 你在做什么。

我推测您需要 hasharray,而不是 time 的数组。也许是这样的:

time_now = Time.now
start_time = time_now.beginning_of_hour.to_datetime.to_i
end_time = (time_now + 3.hours).beginning_of_hour.to_datetime.to_i

@hours = (start_time..end_time).step(1.hour).map {|t| {time_slot: Time.at(t)}}

...并且您可能想要包括 time_slot 当前是否可用:

time_now = Time.now
start_time = time_now.beginning_of_hour.to_datetime.to_i
end_time = (time_now + 3.hours).beginning_of_hour.to_datetime.to_i

@hours = (start_time..end_time).step(1.hour).map do |t| 
  time_slot = Time.at(t)
  {time_slot: time_slot, time_slot_available?: time_slot_available?(time_slot)}
end

...这需要一个 time_slot_available? 方法。出于测试目的,我将其标记为:

def time_slot_available?(time_slot)
  [true, false].sample
end

...这最终会给你这样的东西:

[
  {:time_slot=>2020-08-21 08:00:00 -0700, :time_slot_available?=>false}, 
  {:time_slot=>2020-08-21 09:00:00 -0700, :time_slot_available?=>true}, 
  {:time_slot=>2020-08-21 10:00:00 -0700, :time_slot_available?=>false}, 
  {:time_slot=>2020-08-21 11:00:00 -0700, :time_slot_available?=>false}
]

当然,time_slot_available? 会检查数据库。这种特殊的方法很糟糕,因为它可能产生 N+1,但这只是为了说明目的。

现在,您可以像您描述的那样创建一个单一的、巨大的表单。或者,您可以为每个 time_slot 生成一个没有表单的单选按钮,然后附加一些 javascript,每次单击按钮时都会调用 ajax - 设置 time_slot可用或不可用,视情况而定。

从用户体验的角度来看,我喜欢后者(当用户点击按钮时,工作得到保存),但它是一个偏好、风格、编程技能和可能其他东西的选择。