Rails - 需要有关复杂数据库查询的帮助

时间:2011-09-05 22:00:35

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

我正在构建一个应用程序,用于在计划中分配班次,有或没有关联的员工。也就是说,没有分配员工的Shift在计划中充当占位符。

在任何指定日期,我希望时间表显示该日期的所有班次(连续订购),然后显示未安排在该日期工作的所有剩余员工。

以下是模型:

class Employee < ActiveRecord::Base
  belongs_to :account
  has_many :shifts
end

class Shift < ActiveRecord::Base
  belongs_to :account
  belongs_to :employee

  default_scope order(:starts_at)
end

和我有问题的,可怕的控制器代码(为了简洁而略微编辑):

class SchedulesController < ApplicationController
  include CurrentDateHelper

  def day
    @shifts = @account.shifts.includes(:employee).within(current_date_range).all
    @employees = @account.employees.alphabetically.all

    @employees.reject!{|employee| @shifts.map(&:employee).include? employee}
  end
end

和(非常简化)视图:

<tbody>
  <%- @shifts.each do |shift| -%>
    <%- if shift.employee.present? -%>
      <%- employee = shift.employee -%>
      <%- employee_shifts = shifts.select{|s| s.employee == employee} -%>

      <tr>
        <th><%= employee.name %></th>

        <%- employee_shifts.each do |shift| -%>
          <td><%= shift.timestamp %></td>
        <%- end -%>
      </tr>

    <%- else -%>
      <tr>
        <th>Unassigned</th>
        <td><%= shift.timestamp %></td>
      </tr>
    <%- end -%>
  <%- end -%>

  <%- @employees.each do |shift| -%>
    <tr>
      <th><%= employee.name %></th>
      <td>Click to create a shift for <%= employee.name %></td>
    </tr>
  <%- end -%>
</tbody>

我的问题是,如果/当员工在同一天有多个班次时,员工当前在计划中多次显示。 那,和控制器代码只是丑陋:S

我可能需要按员工对@shifts进行分组,并从那起工作......? 我的SQL排序不是那么好,所以任何指针都非常感激 - 我不一定在寻找复制/粘贴解决方案,更像是一些线索让我深入挖掘和学习。

感谢您阅读本文 - 我希望它有意义! :)

2 个答案:

答案 0 :(得分:1)

你可能是正确的,你想按班次分组,但你可能不希望用SQL做到这一点。您确实希望在视图中访问该数据,并且如果您在SQL中按员工分组,则每个员工只返回一个班次。

相反,你可能想要使用可枚举的group_by,它在视图中看起来像:

<% @shifts.group_by(&:employee).each do |employee, shifts| %>
   <%# do stuff for each 'employee' the grouped array of his/her 'shifts' %>
<% end %>

至于其他部分。您可以排除随班次返回的员工的ID。查看Arel的'not_in'谓词来做到这一点,例如。

ids = @shifts.map {|s| s.employee.try(:id) }.compact
condition = Employee.arel_table[:id].not_in(ids)
@employees = @account.employees.alphabetically.where(condition)

# of if you extracted this into a scope 'exluding' on Employee, it could look like:
@employees = @account.employees.alphabetically.excluding(@shifts.map &:employee)

或者如果您只想替换正在进行的reject!业务,您可以简单地从数组中减去转移持有用户。 e.g:

@employees = @account.employees.alphabetically.all - @shifts.map(&:employee)

答案 1 :(得分:0)

如果您想跳过sql,也可以根据员工ID执行uniq。