1

I have created project, stage, task and sub_task scaffolds:

  • project has a one-to-many association with stage
  • stage has a one-to-many association with task
  • task has one-to-many association with sub_task.

stage, task, and sub_task tables have all a field planned_end_date and status.

Now I want to print the total stages, tasks, sub_tasks that aren't completed until planned_end_date for each project in the projects#index action.

How can I do that in a Rails model?

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

what i have tried-

project#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>

what is code does is prints total number of pending stages, tasks and sub_tasks for all projects and prints same count for every project. I want to print pending stages+tasks+sub_tasks for every project's total pending stages+tasks+sub_tasks. what

1 Answer 1

3

Yes, you're counting for ALL projects, not just for the current project.

What you want is...

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

note we're using project.id which references the current project in the each loop, not @projects which is all projects.

Better might be...

<% stages = project.stages %>

And better from a performance standpoint is to let the database give you the count...

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

If you're going to do complex boolean tests, it helps to use brackets to ensure you've got the correct order of precedence,

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

You can do similar with tasks and sub-tasks by defining the relationship in the model...

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

This will let you do project.tasks and project.sub_tasks

Note that you may want to move these calculations into the model...

class Project

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

Which is better, and will let you do...

<% project.incomplete_stages_count %>

but even then it means the Project model needs to know what makes a stage incomplete, which is a headache if you ever change the business rules, so maybe create a scope in Stage

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

And in Project

class Project
  def incomplete_stages_count
    stages.incomplete.count
  end
end
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.