在 Rails Ruby 中导出到 CSV 并汇总小时数
Exporting to CSV and Summing hours in Ruby on Rails
我有一个 Rails 3.2.21 应用程序,我正在其中构建时钟功能。我目前正在编写一个应该执行以下操作的 to_csv
方法:
创建一个包含列名的 header 行
遍历输入(记录)块并显示员工用户名、clock_in、clock_out、站点和评论 objects,最后在块的最后一行显示总小时数.
我想在每个用户之间显示他们的总小时数。正如您在 to_csv
方法中看到的那样,我可以通过将 csv << [TimeFormatter.format_time(ce.user.clock_events.sum(&:total_hours))]
的数组铲入 CSV 来使其工作 "hackish"。最终结果是它确实为每个员工 clock_events 提供了正确的总小时数,但它会在每次输入后重复它,因为我显然是在迭代一个块。
我想找出一种方法将其抽象到块外,并弄清楚如何铲入另一个数组,该数组计算 total_hours 用户的所有时钟事件而没有重复条目。
以下是我的模型,所以如果有什么不清楚的地方,请告诉我。另外,如果我的问题令人困惑或没有意义,请告诉我,我很乐意澄清。
class ClockEvent < ActiveRecord::Base
attr_accessible :clock_in, :clock_out, :user_id, :station_id, :comment
belongs_to :user
belongs_to :station
scope :incomplete, -> { where(clock_out: nil) }
scope :complete, -> { where("clock_out IS NOT NULL") }
scope :current_week, -> {where("clock_in BETWEEN ? AND ?", Time.zone.now.beginning_of_week - 1.day, Time.zone.now.end_of_week - 1.day)}
scope :search_between, lambda { |start_date, end_date| where("clock_in BETWEEN ? AND ?", start_date.beginning_of_day, end_date.end_of_day)}
scope :search_by_start_date, lambda { |start_date| where('clock_in BETWEEN ? AND ?', start_date.beginning_of_day, start_date.end_of_day) }
scope :search_by_end_date, lambda { |end_date| where('clock_in BETWEEN ? AND ?', end_date.beginning_of_day, end_date.end_of_day) }
def punch_in(station_id)
self.clock_in = Time.zone.now
self.station_id = station_id
end
def punch_out
self.clock_out = Time.zone.now
end
def completed?
clock_in.present? && clock_out.present?
end
def total_hours
self.clock_out.to_i - self.clock_in.to_i
end
def formatted_clock_in
clock_in.try(:strftime, "%m/%d/%y-%H:%M")
end
def formatted_clock_out
clock_out.try(:strftime, "%m/%d/%y-%H:%M")
end
def self.search(search)
search ||= { type: "all" }
results = scoped
# If searching with BOTH a start and end date
if search[:start_date].present? && search[:end_date].present?
results = results.search_between(Date.parse(search[:start_date]), Date.parse(search[:end_date]))
# If search with any other date parameters (including none)
else
results = results.search_by_start_date(Date.parse(search[:start_date])) if search[:start_date].present?
results = results.search_by_end_date(Date.parse(search[:end_date])) if search[:end_date].present?
end
results
end
def self.to_csv(records = [], options = {})
CSV.generate(options) do |csv|
csv << ["Employee", "Clock-In", "Clock-Out", "Station", "Comment", "Total Shift Hours"]
records.each do |ce|
csv << [ce.user.try(:username), ce.formatted_clock_in, ce.formatted_clock_out, ce.station.try(:station_name), ce.comment, TimeFormatter.format_time(ce.total_hours)]
csv << [TimeFormatter.format_time(ce.user.clock_events.sum(&:total_hours))]
end
csv << [TimeFormatter.format_time(records.sum(&:total_hours))]
end
end
end
在朋友的帮助和研究 APIdocs 的帮助下,我能够重构该方法:
def self.to_csv(records = [], options = {})
CSV.generate(options) do |csv|
csv << ["Employee", "Clock-In", "Clock-Out", "Station", "Comment", "Total Shift Hours"]
# records.group_by{ |r| r.user }.each do |user, records|
records.each do |ce|
csv << [ce.user.try(:username), ce.formatted_clock_in, ce.formatted_clock_out, ce.station.try(:station_name), ce.comment, TimeFormatter.format_time(ce.total_hours)]
#csv << [TimeFormatter.format_time(records.select{ |r| r.user == ce.user }.sum(&:total_hours))]
end
records.map(&:user).uniq.each do |user|
csv << ["Total Hours for: #{user.username}"]
csv << [TimeFormatter.format_time(records.select{ |r| r.user == user}.sum(&:total_hours))]
end
csv << ["Total Payroll Hours"]
csv << [TimeFormatter.format_time(records.sum(&:total_hours))]
end
end
我有一个 Rails 3.2.21 应用程序,我正在其中构建时钟功能。我目前正在编写一个应该执行以下操作的 to_csv
方法:
创建一个包含列名的 header 行 遍历输入(记录)块并显示员工用户名、clock_in、clock_out、站点和评论 objects,最后在块的最后一行显示总小时数.
我想在每个用户之间显示他们的总小时数。正如您在 to_csv
方法中看到的那样,我可以通过将 csv << [TimeFormatter.format_time(ce.user.clock_events.sum(&:total_hours))]
的数组铲入 CSV 来使其工作 "hackish"。最终结果是它确实为每个员工 clock_events 提供了正确的总小时数,但它会在每次输入后重复它,因为我显然是在迭代一个块。
我想找出一种方法将其抽象到块外,并弄清楚如何铲入另一个数组,该数组计算 total_hours 用户的所有时钟事件而没有重复条目。
以下是我的模型,所以如果有什么不清楚的地方,请告诉我。另外,如果我的问题令人困惑或没有意义,请告诉我,我很乐意澄清。
class ClockEvent < ActiveRecord::Base
attr_accessible :clock_in, :clock_out, :user_id, :station_id, :comment
belongs_to :user
belongs_to :station
scope :incomplete, -> { where(clock_out: nil) }
scope :complete, -> { where("clock_out IS NOT NULL") }
scope :current_week, -> {where("clock_in BETWEEN ? AND ?", Time.zone.now.beginning_of_week - 1.day, Time.zone.now.end_of_week - 1.day)}
scope :search_between, lambda { |start_date, end_date| where("clock_in BETWEEN ? AND ?", start_date.beginning_of_day, end_date.end_of_day)}
scope :search_by_start_date, lambda { |start_date| where('clock_in BETWEEN ? AND ?', start_date.beginning_of_day, start_date.end_of_day) }
scope :search_by_end_date, lambda { |end_date| where('clock_in BETWEEN ? AND ?', end_date.beginning_of_day, end_date.end_of_day) }
def punch_in(station_id)
self.clock_in = Time.zone.now
self.station_id = station_id
end
def punch_out
self.clock_out = Time.zone.now
end
def completed?
clock_in.present? && clock_out.present?
end
def total_hours
self.clock_out.to_i - self.clock_in.to_i
end
def formatted_clock_in
clock_in.try(:strftime, "%m/%d/%y-%H:%M")
end
def formatted_clock_out
clock_out.try(:strftime, "%m/%d/%y-%H:%M")
end
def self.search(search)
search ||= { type: "all" }
results = scoped
# If searching with BOTH a start and end date
if search[:start_date].present? && search[:end_date].present?
results = results.search_between(Date.parse(search[:start_date]), Date.parse(search[:end_date]))
# If search with any other date parameters (including none)
else
results = results.search_by_start_date(Date.parse(search[:start_date])) if search[:start_date].present?
results = results.search_by_end_date(Date.parse(search[:end_date])) if search[:end_date].present?
end
results
end
def self.to_csv(records = [], options = {})
CSV.generate(options) do |csv|
csv << ["Employee", "Clock-In", "Clock-Out", "Station", "Comment", "Total Shift Hours"]
records.each do |ce|
csv << [ce.user.try(:username), ce.formatted_clock_in, ce.formatted_clock_out, ce.station.try(:station_name), ce.comment, TimeFormatter.format_time(ce.total_hours)]
csv << [TimeFormatter.format_time(ce.user.clock_events.sum(&:total_hours))]
end
csv << [TimeFormatter.format_time(records.sum(&:total_hours))]
end
end
end
在朋友的帮助和研究 APIdocs 的帮助下,我能够重构该方法:
def self.to_csv(records = [], options = {})
CSV.generate(options) do |csv|
csv << ["Employee", "Clock-In", "Clock-Out", "Station", "Comment", "Total Shift Hours"]
# records.group_by{ |r| r.user }.each do |user, records|
records.each do |ce|
csv << [ce.user.try(:username), ce.formatted_clock_in, ce.formatted_clock_out, ce.station.try(:station_name), ce.comment, TimeFormatter.format_time(ce.total_hours)]
#csv << [TimeFormatter.format_time(records.select{ |r| r.user == ce.user }.sum(&:total_hours))]
end
records.map(&:user).uniq.each do |user|
csv << ["Total Hours for: #{user.username}"]
csv << [TimeFormatter.format_time(records.select{ |r| r.user == user}.sum(&:total_hours))]
end
csv << ["Total Payroll Hours"]
csv << [TimeFormatter.format_time(records.sum(&:total_hours))]
end
end