【问题标题】:How group_by on Rails如何在 Rails 上进行 group_by
【发布时间】:2016-09-16 01:11:15
【问题描述】:

我对 ROR 很陌生,但我很难做到这一点。

我有一个 Working_hour 模型和一个 Merchant 模型,其中商家 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 教程,但我没有用于 working_hour 模型的控制器。有任何想法吗?

【问题讨论】:

  • 看起来您的视图中已获得所需的所有数据。你只需要正确地操作它。也许从您的角度发布代码?
  • 我编辑了我的问题。本做那件事简单吗?

标签: ruby-on-rails group-by


【解决方案1】:

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

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

这意味着您的 .each 现在将应用于哈希结构,其中键成为整数或您分组的事物,在这种情况下,天也恰好是整数,和一个匹配的子集合,但您 grouped_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 %>

作为

<% @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,您必须重新格式化它,我敢肯定。

【讨论】:

  • 谢谢。现在这行得通。 =) 有没有推荐给新手学习 SQL 组的资料?
  • 这是一篇不错的文章? alexpeattie.com/blog/…
  • 是的,主要是 google-fu 或您当地的图书馆。 SQL 的核心并没有太大变化,因此您库中的大部分内容都应该是相关的。如果你使用 MySQL 并且想要速度,我刚开始时推荐这个,shop.oreilly.com/product/0636920022343.do
【解决方案2】:

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

散列中的 keys 将是 t(:"date.abbr_day_names")[wh.day.to_i]values 将是 wh.open_time.to_formatted_s(:time) - wh.close_time.to_formatted_s(:time)array

@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

结束

然后您可以使用 @merchant_working_hours 哈希

<% @merchant_working_hours.each do |key,value| %>
<%= key: value%>
<% end %>

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    • 2019-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多