ruby-on-rails - 在我的 Rails 应用程序中计算加班的最佳方法是什么?
问题描述
嗨,我正在为自己构建一个小型 Rails 会议应用程序。我有一张名为 Meetings 的表格,有 5 列
name:string start_date:datime end_date:datetime duration:integer overtime:integer
我的问题是是否有比我正在做的更好的计算加班时间的方法?
持续时间是每天 start_date 和 end_date 之间的总时间,每天可以有多个会议。
加班时间是每天的总持续时间减去 7 小时 25 分钟(26700 秒),每天超过 7.25 的任何总会议持续时间都是加班时间。我得到了我想要的结果(见下图),但我想知道是否有更好的方法?我在 index.html.erb 中使用了 if 语句。得到我想要的结果,因为保存到数据库的加班数据不是我需要的实际加班数据。
从下图中,我通常只希望将“22 分钟和 40 分钟”保存为整数。我还想展示每周的总加班时间,这就是为什么我认为我的方式行不通的原因。他们是更好的方法吗?
提前感谢任何输入。
我的 Meeting.rb 模型文件中的两个计算列持续时间和加班时间
class Meeting < ApplicationRecord
#callbacks save to db
before_save :set_duration
before_save :daily_total_ot
#calculate duration
def set_duration
self.duration = (end_date - start_date).to_i
end
#Calculate total duration for each day
def daily_total_duration
Meeting.where("start_date >= ? AND end_date < ?", self.start_date.beginning_of_day, self.start_date.end_of_day).sum(:duration)
end
#calculate total overtime for each day
def daily_total_ot
self.overtime = Meeting.where("start_date >= ? AND end_date < ?", self.start_date.beginning_of_day, self.start_date.end_of_day).sum(:duration) - 26700.to_i
end
end
在我看来,我有会议 .index.html.erb
<h1>Meetings</h1><%= Time.zone.now.strftime('%d-%b-%Y') %>
<table class="table">
<thead class="thead-dark">
<tr>
<th>Start date</th>
<th>End date</th>
<th>Duration</th>
<th>Duration Time</th>
<th>Daily Total <br>Duration</th>
<th>overtime saved</th>
<th>Real OT</th>
<th>Show</th>
<th>Edit</th>
<th>Destroy</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @meetings.each do |meeting| %>
<tr>
<td><%= meeting.name %></td>
<td><%= meeting.start_date.strftime("%d-%b-%Y %I:%M %p") %></td>
<td><%= meeting.end_date.strftime("%d-%b-%Y %I:%M %p") %></td>
<td><%= meeting.duration %></td>
<td><%= Time.at(meeting.daily_total_duration).utc.strftime("%H hours and %M minutes ") %></td>
<td><%= meeting.daily_total_ot %></td>
<% if (meeting.daily_total_duration) > 26700 %>
<td><%= Time.at(meeting.daily_total_ot).utc.strftime("%H hours and %M minutes ") %></td>
<% else %>
<td>No Overtime</td>
<% end %>
<td><%= link_to 'Show', meeting %></td>
<td><%= link_to 'Edit', edit_meeting_path(meeting) %></td>
<td><%= link_to 'Destroy', meeting, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br><br>
解决方案
当前方法的问题是,您无法再次“保存”任何会议,否则会计算错误。
加班的“正确”查询是
def previous_meetings_for_same_day
# meeting should start today ...
start = start_date.beginning_of_day
# ...and finish before this one
limit = end_date - 1.second
# notice the use of open ranges instead of raw SQL
Meeting.where(start_date: start.., end_date: ..limit)
end
def daily_total_duration
previous_meetings_for_same_day.sum(:duration).to_i + duration
end
def computed_overtime
# clamp "forces" a value to fit in the given range
# in this case if the receiver is negative, it returns 0
(daily_total_duration - 26700).clamp(0..)
end
def daily_total_ot
self.overtime = computed_overtime
end
这样,较早的会议将被考虑到以后的会议,而不是相反。
通过限制差异,您还可以避免保存负值。
更新:
如果您使用 PostgreSQL,则可以使用映射到ActiveSupport::Duration
ruby 中的“interval”类型。
这样,这些方法会发生一些变化,因为它们不再是整数了:
MAX_DAILY_DURATION = 7.hours + 25.minutes
def set_duration
self.duration = end_date - start_date
end
def daily_total_duration
previous_meetings_for_same_day.sum(:duration) + duration
end
def computed_overtime
# clamp "forces" a value to fit in the given range
# in this case if the receiver is negative, it returns 0
(daily_total_duration - MAX_DAILY_DURATION).clamp(0.seconds..)
end
def daily_total_ot
self.overtime = computed_overtime
end
推荐阅读
- javascript - 将端点的值分配给复选框
- java - 同步来自不同对象的线程 -{EDITED}
- javascript - vue.js(2) window.scrollY 总是返回 0
- python - 作为 Python 代码运行和评估导入的文本文件
- google-chrome - rel="preload" 在 Firefox 和新的 Internet Explorer 中不起作用
- c# - 索引超出范围错误 C#/Unity,我不确定哪里出错了
- ruby - NeoVim 在 MacOS 上不使用 rbenv 指定的 ruby
- assembly - 如何从 arm 组件中调用函数?(分段错误)
- python - 在 Python 数据类中使用默认 uuid 值
- javascript - Firebase 和 auth 属性在 Ionic 和 Firebase 中不存在