Как выполнить расчет в модели рельсов?

Я создал каркасы проекта, этапа, задачи и подзадачи:

  • project имеет связь "один ко многим" с stage
  • stage имеет связь "один ко многим" с task
  • task имеет связь "один ко многим" с sub_task.

Все таблицы stage, task и sub_task содержат поля planned_end_date и status.

Теперь я хочу распечатать общее количество этапов, задач, подзадач, которые не завершены до planned_end_date для каждого project в projects#index действии.

Как я могу сделать это в модели 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>

что делает код, так это печатает общее количество ожидающих этапов, задач и подзадач для всех проектов и печатает одинаковое количество для каждого проекта. Я хочу распечатать незавершенные этапы + задачи + под_задачи для всех ожидающих выполнения этапов + задач + под_задач каждого проекта. Какие


person rock    schedule 09.03.2020    source источник


Ответы (1)


Да, вы считаете ВСЕ проекты, а не только текущий проект.

То, что вы хотите, это...

<% 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.tasks и project.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
person SteveTurczyn    schedule 09.03.2020