如何在rails模型中进行计算?

How to perform calculation in rails model?

我已经创建了项目、阶段、任务和 sub_task 个脚手架:

stagetasksub_task 表都有一个字段 planned_end_datestatus.

现在我想为 projects#index 操作中的每个 project 打印直到 planned_end_date 才完成的总阶段、任务、sub_task。

如何在 Rails 模型中做到这一点?

class Project < ApplicationRecord
  has_many :stages, dependent: :destroy
  validate :end_after_start

  private
  def end_after_start
    return if to_date.blank? || form_date.blank?

    if to_date < form_date
      errors.add(:to_date, "Project end date must be same or after the start date")
    end
  end
end

我试过的-

项目#index.html.erb

      <% @projects.each do |project| %>
        <tr>
          <td><%= project.project_name %></td>

          <%  @stages = Stage.where(project_id: @projects.ids) %>
          <%  @tasks = Task.where(stage_id: @stages.ids) %>
          <%  @sub_tasks = SubTask.where(task_id: @tasks.ids) %>

          <%  stage_counter = 0 %>
          <%  task_counter = 0 %>
          <%  sub_task_counter = 0 %>

          <%  @stages.each{|s| stage_counter += 1 if s.planned_end_date.past? && s.status == 0 || s.planned_end_date.past? && s.status == 2} %>
          <%  @tasks.each{|s| task_counter += 1 if s.planned_end_date.past? && s.status == 0 || s.planned_end_date.past? && s.status == 2} %>
          <%  @sub_tasks.each{|s| sub_task_counter += 1 if s.planned_end_date.past? && s.status == 0 || s.planned_end_date.past? && s.status == 2} %>

          <% @count =0 %>
          <%  @count = stage_counter + task_counter + sub_task_counter %>

          <td><span class="alert"><%= @count.to_s + " Activity Pending" %></span></td>

代码的作用是打印所有项目的待处理阶段、任务和 sub_task 的总数,并为每个项目打印相同的计数。我想为每个项目的总待处理阶段+任务+sub_tasks 打印待处理阶段+任务+sub_tasks。 什么

是的,您计算的是所有项目,而不仅仅是当前项目。

你想要的是...

<% stages = Stage.where(project_id: project.id) %>

请注意,我们使用的是 project.id,它引用每个循环中的当前项目,而不是 @projects,它是所有项目。

更好的可能是...

<% stages = project.stages %>

从性能的角度来看,更好的方法是让数据库为您提供计数...

<% stage_counters = project.stages.where('planned_end_date < ?', Date.today).where(status: [0,2]).count %>

如果您要进行复杂的布尔测试,使用括号有助于确保您获得正确的优先顺序,

<%  @stages.each{|s| stage_counter += 1 if (s.planned_end_date.past? && s.status == 0) || (s.planned_end_date.past? && s.status == 2)} %>

您可以通过在模型中定义关系来对任务和子任务执行类似的操作...

has_many :stages, dependent: :destroy
has_many :tasks, through: :stages
has_many :sub_tasks, through: :tasks

这会让你做 project.tasksproject.sub_tasks

请注意,您可能希望将这些计算移至模型中...

class Project

  def incomplete_stages_count
    stages.where('planned_end_date < ?', Date.today).where(status: [0,2]).count
  end

哪个更好,会让你做...

<% project.incomplete_stages_count %>

但即便如此,这也意味着项目模型需要知道是什么导致阶段不完整,如果您更改业务规则,这将是一件令人头疼的事情,因此也许可以在阶段中创建一个范围

class Stage
  scope :incomplete, -> {where('planned_end_date < ?', Date.today).where(status: [0,2])}
end

并且在项目中

class Project
  def incomplete_stages_count
    stages.incomplete.count
  end
end