Search code examples
ruby-on-railsrubyrecurring-eventsice-cube

Handling recurring tasks in Rails


I've been trying to build a customised to-do app with a possibility to add recurring tasks.

My first approach was to use recurring_select on the front and ice_cube logic in the back. I managed to generate a schedule with all desired occurrences but the problem I encountered is that this way I can no longer mark a recurring task as complete, as it's only its occurrence that's displaying.

Here's some of the code:

*task.rb*
class Task < ApplicationRecord
  (...)
  serialize :recurrence, Hash

  def recurrence=(value)
    # byebug
    if value != "null" && RecurringSelect.is_valid_rule?(value)
      super(RecurringSelect.dirty_hash_to_rule(value).to_hash)
    else
      super(nil)
    end
  end

  def rule
    IceCube::Rule.from_hash recurrence
  end

  def schedule(start)
    schedule = IceCube::Schedule.new(start)
    schedule.add_recurrence_rule(rule)
    schedule
  end

  def display_tasks(start)
    if recurrence.empty?
      [self]
    else
      start_date = start.beginning_of_week
      end_date = start.end_of_week
      schedule(start_date).occurrences(end_date).map do |date|
          Task.new(id: id, name: name, start_time: date)
      end
    end
  end
end  

*tasks_controller.rb*
class TasksController < ApplicationController
  before_action :set_task, only: [:complete, :uncomplete, :show]
  (...)
  def index
    (...)

    @display_tasks = @tasks.flat_map{ |t| t.display_tasks(params.fetch(:start_date, Time.zone.now).to_date ) }
  end
  (...)
end

I was wondering if there's maybe a better way to approach it than using the gems? I was reading about scheduling rake tasks but I've never done it myself so I'm not sure if that's the way to go either.

Thanks in advance.


Solution

  • Yes, there is a better way to do recurring tasks using rake tasks and whenever gem. It has an extremely easy to used DSL

    All you need to do is define your rake task and then put the schedule configuration inside a schedule.rb.

    However, whenever utilizes cron jobs and is not supported by Heroku. If you are using Heroku, then you should use Heroku Scheduler. All you need to do is define your tasks in a tasks/scheduler.rake, install the addon and let Heroku Scheduler do the rest.

    This approaches will help keep your models cleaner and remove the scheduling information from them.

    To the second part of your question that is marking recurring tasks as complete, all you need to do is set a boolean attribute say completed to true when the recurring task is marked as complete and then adding a guard clause in your rake tasks like return if task.completed? to skip processing for that task.