【问题标题】:How would I group a list of appointments by date?如何按日期对约会列表进行分组?
【发布时间】:2012-10-17 02:13:54
【问题描述】:

我正在返回一个约会列表。

现在它们看起来像这样:

-Jan 1
--appointment @230
-Jan 1
--appointment @3
-Jan 1
--appointment @4
-Jan 2
--appointment @4
-Jan 2
--appointment @5

我想像这样返回列表

-Jan 1
--appointment @230
--appointment @3
--appointment @4
-Jan 2
--appointment @4
--appointment @5

约会有一个“start_at”字段,它是一个日期时间。比较简单。只是不确定如何遍历集合,然后以最合理的方式对其进行分组。

谢谢。

用户(是用户或培训师) has_many :约会 has_many :trainer_appointments, :class_name => "约会", :foreign_key => "trainer_id"

约会

# Table name: appointments
#
#  id         :integer          not null, primary key
#  trainer_id :integer
#  start_at   :datetime
#  created_at :datetime         not null
#  updated_at :datetime         not null
#  user_id    :integer

这里有一些播放代码: u.trainer_appointments

=> [#<Appointment id: 6, trainer_id: 1, start_at: "2012-11-18 13:08:00", created_at: "2012-10-17 02:01:42", updated_at: "2012-10-17 02:01:42", user_id: 2>, #<Appointment id: 7, trainer_id: 1, start_at: "2012-11-18 13:08:00", created_at: "2012-10-17 02:02:00", updated_at: "2012-10-17 02:02:00", user_id: 2>, #<Appointment id: 8, trainer_id: 1, start_at: "2012-11-24 13:08:00", created_at: "2012-10-17 02:03:28", updated_at: "2012-10-17 02:03:28", user_id: 2>] 

返回 3 个约会。两个在同一天。 1 在不同的日子。

希望以按日期分组的方式返回它。 我尝试过这样的事情来弄清楚但迷路了:

u.trainer_appointments.collect {|each| each.start_at}.uniq.collect {|each| u.trainer_appointments.find_by_start_at(each.to_date.beginning_of_day..each.to_date.end_of_day)}

返回两个约会。两个日期之间。第一天错过了第二个。

我知道代码在很多层面上都是错误的。我只是想玩弄迭代。虽然没有得到我想要的。可能是因为 uniq 以某种方式限制了返回大小,即使我期望在最终数组中返回一个范围。

我不确定迭代分组需要什么实际结构。这不是我的专长。数组中的数组分组?我将如何在视图中对其进行迭代?

谢谢。

【问题讨论】:

  • 你的代码是什么样的?如果我们看到您在做什么,而不仅仅是结果和期望的结果,则更容易尝试和提供帮助。
  • 添加示例。谢谢和抱歉。

标签: ruby ruby-on-rails-3 activerecord


【解决方案1】:

用户 group_by 在您的收藏中。

Ruby implementation 要求传递给它的表达式计算为布尔值。

Rails implementation 允许您传入一列并按该列分组。

你的代码应该是这样的

u.trainer_appointments.
  collect {|a| a.start_at}.
  uniq.collect {|b| 
    u.trainer_appointments.
    group_by(b.to_date.beginning_of_day..b.to_date.end_of_day)
  }

find_by_start_at 替换为group_by

编辑:确定范围!

# in User model (or the model for current_user)
class User < ActiveRecord::Base
  scope :mine, where(:trainer_id => current_user)
  scope :days!, where(:start_at.to_date.beginning_of_day)
  # the ! is there because "days" is a Ruby method
end

# in controller...
@client_appointments = @client.appointments.mine.group_by(&:days!)

注意:我不确定是group_by(days!)group_by(:days!) 还是group_by(&amp;:days!)。您可能需要尝试一下,看看有什么适合您的。

【讨论】:

  • 感谢您的评论阐明了如何以更好的方式做到这一点。我最终做了这样的事情:@client_appointments = @client.appointments.find(:all, :conditions => {:trainer_id => current_user}).group_by {|a| a.start_at.to_date.beginning_of_day }
  • 您也可以使用作用域使代码更具可读性。我已经编辑了关于如何使用您在评论中发送的当前代码行来完成此操作的答案。
【解决方案2】:

如果你不使用数据库的分组功能,最简单的方法是使用块:

require 'date'

# Make some test data
Appointment = Struct.new(:start_at)
data = ['2012-01-01 14:30', '2012-01-01 15:00', '2012-01-01 16:00',
 '2012-01-02 16:00', '2012-01-02 17:00']

appointments = data.map do |time|
  Appointment.new DateTime.parse(time)
end

# Use chunk to group array elements
appointments.
  sort { |a,b| b.start_at <=> a.start_at }. # always sort before chunking
  chunk { |appt| appt.start_at.to_date }. # chunk on day of the appointment
  each do |day, appts| # chunk emits two-element arrays
    puts
    puts "Day " + day.to_s
    appts.each { |appt| puts appt.start_at.strftime('%H:%M') }
  end

输出:

Day 2012-01-02
17:00
16:00

Day 2012-01-01
16:00
15:00
14:30

【讨论】:

  • 天哪,Chunk 很复杂。我明白了。谢谢你教我。为了方便起见,我将使用 ActiveRecord group_by,但是如果我曾经使用过 Mongoid 之类的东西,那么如果数据库不支持 group_by,我知道一种方法。
【解决方案3】:

最终使用了以下内容:

    @client_appointments = @client.appointments.find(:all, :conditions => {:trainer_id => current_user}).group_by {|a| a.start_at.to_date.beginning_of_day }

然后像这样迭代它:

- @client_appointments.sort.each do |month, appointments|
  %h2
    = month.to_s(:day_month)
  = render appointments

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 2016-09-09
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多