Assigning a date relative to another record's date

45 views Asked by At

I'm building a Rails 4.2+ application that has Workflows and Tasks. A task.due_date can either be a specified date (such as "01/01/2017") or it can be relative to a date on the parent workflow record.

class Workflow < ApplicationRecord
  # closing_date:date

  after_save :update_relative_tasks

  has_many :tasks

  # Production code would make sure closing_date changed before updating associations
  def update_relative_tasks
    tasks.where(has_relative_date: true).each do |task|
      task.update_relative_due_date(closing_date)
    end
  end
end

class Task < ApplicationRecord
  # due_date:date
  # has_relative_date:boolean (default: false)
  # number:integer (default: 0)
  # days_or_weeks:string (default: "days")
  # before_or_after:string (default: "after")
  # workflow:references

  belongs_to :workflow

  def number_of_days
    @number_of_days ||= if days_or_weeks == "weeks"
      number * 7 # relative date is in "weeks"
    else
      number # assume relative date is in "days"
    end
  end

  # Pseudo-ish code, not tested, but shows concept
  def update_relative_due_date(date)
    new_due_date = if before_or_after == "before"
      date - number_of_days.days
    else
      date + number_of_days.days
    end

   update_attribute(:due_date, new_due_date)
  end
end

Assigning a specific date on the task is simple, I just use a calendar widget and it sets the date, no problem.

The tricky part is assigning a relative task.due_date based off of the workflow.closing_date.

For example, let's say the workflow.closing_date is 01/01/2017 and I want to have a task due 5 days before (or after) that date.

I can add some form fields that do something like, where the brackets represent input fields:

Due Date: [x] number of [days|weeks] [before|after] workflow.closing_date

and then I can parse that out in Ruby code and update the task with the proper due_date.

However, if the workflow.closing_date changes, I then would need to go find all the associated tasks and re-calculate their relative dates. Also, if the workflow.closing_date wasn't known initially and it was added later on, it would again need to re-calculate the due dates for all associated tasks.

Eventually I'm also going to add reminders to tasks, and those also will be relative to the task.due_date. Very similar to how Google Calendar's notifications work.

How is something like this solved? I know I'll need to add a background processor to handle sending reminders. But I'm uncertain how to solve the issue of setting a task.due_date relative to some date on another record.

1

There are 1 answers

1
SerKnight On

I may be missing the difficulty in this issue so will try to talk through it. Could you set an after_save filter on workflow to handle any changes to related object if the workflow is saved?

workflow.rb

after_save :update_due_date

def update_due_date
   self.tasks.update_all(due_date: self.closing_date + 5.days)
end

This way the tasks closing dates are always relative to the workflows closing_date and you don't have to worry about complicated update logic. Maybe I missed something above..