如何在Rails上进行group_by

时间:2016-09-15 15:55:25

标签: ruby-on-rails group-by

我对ROR很新,我很难实现这个目标。

我有一个Working_hour模型和一个商家模型,其中商家has_many working_hours和working_hour属于Merchant,如下所示:

class Merchant < ApplicationRecord 
  has_many   :working_hours, inverse_of: :merchant, dependent: :destroy
  accepts_nested_attributes_for :working_hours, reject_if: :all_blank, allow_destroy: true
end

工作时间表

create_table "working_hours", force: :cascade do |t|
  t.integer  "day"
  t.time     "open_time"
  t.time     "close_time"
  t.integer  "merchant_id"
  t.datetime "created_at",  null: false
  t.datetime "updated_at",  null: false
  t.index ["merchant_id"], name: "index_working_hours_on_merchant_id"
end

商家可以在同一天有两个工作小时。

我的观点:

<% @merchant.working_hours.order(:day).each do |wh| %>
  <li>
    <%= t(:"date.abbr_day_names")[wh.day.to_i] %> : 
    <%= wh.open_time.to_formatted_s(:time)  %> -
    <%= wh.close_time.to_formatted_s(:time)  %>
  </li>
<% end %>

当我在按日排序的视图中显示时,检索到的数据是:

Mon: 10:00-13:00
Mon: 17:00-20:00
Tue: 10:00-13:00
Tue: 17:00-21:00
Wed: 10:00-13:00

如何按天计算working_hours并以这种方式显示:

Mon: 10:00-13:00 / 17:00-20:00
Tue: 10:00-13:00 / 17:00-21:00
Wed: 10:00-13:00

我在Railscast上观看了group_by教程,但是我没有一个控制器来工作我的模型。有任何想法吗?

2 个答案:

答案 0 :(得分:1)

您可以使用ruby Enumerator的group_by,它会为您提供一个具有结构的新集合

{ 
  key: matching collection items (minus item grouped on), 
  key2: matching collection items (minus item grouped on)
}

这意味着您的 .each 现在将应用于Hash结构,其中键变为整数或分组的东西,在这种情况下,天也恰好是整数,和一个匹配的子集合,但具有您从其中删除的groups_by属性。所以在你的情况下你可以重写

<% @merchant.working_hours.order(:day).each do |wh| %>
  <li>
    <%= t(:"date.abbr_day_names")[wh.day.to_i] %> : 
    <%= wh.open_time.to_formatted_s(:time)  %> -
    <%= wh.close_time.to_formatted_s(:time)  %>
  </li>
<% end %>

as

<% @merchant.working_hours.order(:day).group_by(&:day).each do |day, whs| %>
  <%= t(:"date.abbr_day_names")[day.to_i] %> : 
  <%= whs.each_with_index do |wh, index| %>
    <li>
      <%= wh.open_time.to_formatted_s(:time)  %> -
      <%= wh.close_time.to_formatted_s(:time)  %>
    </li>
    <%# if we have more than one entry add slash %>
    <%= if index > 0 %>
      /
    <% end %>
  <% end %>
<% end %>

请注意,这意味着所有分组都在ruby图层上完成,这会导致大型数据集出现问题,而且您现在也处于ruby图层中,因此您将失去AREL延迟加载功能,例如:现在必须在ruby中完成排序,而不是将新的SQL顺序应用于“子集合”。理想情况下,你想要一个SQL组,但那是另一个时间。

注意我没有测试这个代码所以它可能会爆炸... YMMV你必须重新格式化它我确定。

答案 1 :(得分:1)

您可以将值保存在哈希中,并使用它以所需格式进行打印。

哈希中的将为t(:"date.abbr_day_names")[wh.day.to_i],而将为 数组 {1}}

wh.open_time.to_formatted_s(:time) - wh.close_time.to_formatted_s(:time)

然后,您可以使用 @merchant_working_hours 哈希

@merchant_working_hours = {}
@merchant.working_hours.order(:day).each do |wh|
@merchant_working_hours[t(:"date.abbr_day_names")[wh.day.to_i].to_s] ||= []
@merchant_working_hours[t(:"date.abbr_day_names")[wh.day.to_i].to_s] = wh.open_time.to_formatted_s(:time).to_s + '-' +  wh.close_time.to_formatted_s(:time).to_s

以所需格式打印值,如果您有超过一周的数据,则可以使用创建时间和更新值或打开时间和关闭时间来检查当天是否存在。