Recurring Events with FullCalendar

#94 Recurring Events with FullCalendar
8/20/2017

Summary

Create recurring events and interact with them on FullCalendar.
4
rails view calendar javascript ajax 8:30 min

Resources

Be sure to checkout the previous episodes as they cover much of the prerequisite information.

Episode 42 - Full Calendar Events and Scheduling
Episode 93 - Recurring Events with ice_cube

Source - https://github.com/driftingruby/094-recurring-events-on-full-calendar

Summary

Gemfilesource 'https://rails-assets.org' do
  gem 'rails-assets-fullcalendar'
  gem 'rails-assets-momentjs'
end

gem 'ice_cube'
recurring_events_migration.rb# rails g model recurring_event title anchor:date frequency:integer color

class CreateRecurringEvents < ActiveRecord::Migration[5.0]
  def change
    create_table :recurring_events do |t|
      t.string :title
      t.date :anchor
      t.integer :frequency, limit: 1, default: 0
      t.string :color

      t.timestamps
    end
  end
end
recurring_events_controller.rbclass RecurringEventsController < ApplicationController
  before_action :set_recurring_event, only: [:show, :edit, :update, :destroy]

  def index
    @recurring_events = RecurringEvent.all
  end

  def show
  end

  def new
    @recurring_event = RecurringEvent.new
  end

  def edit
  end

  def create
    @recurring_event = RecurringEvent.new(recurring_event_params)
    @recurring_event.save
  end

  def update
    if params[:event]
      @recurring_event.update(anchor: params[:event][:start])
    else
      @recurring_event.update(recurring_event_params)
    end
  end

  def destroy
    @recurring_event.destroy
  end

  private
  
  def set_recurring_event
    @recurring_event = RecurringEvent.find(params[:id])
  end

  def recurring_event_params
    params.require(:recurring_event).permit(:title, :anchor, :frequency, :color)
  end
end
recurring_event.rbclass RecurringEvent < ApplicationRecord
  enum frequency: { weekly: 0, biweekly: 1, monthly: 2, annually: 3 }

  validates :anchor, presence: true
  validates :frequency, presence: true

  def schedule
    @schedule ||= begin
      schedule = IceCube::Schedule.new(now = anchor)
      case frequency      
      when 'weekly'
        schedule.add_recurrence_rule IceCube::Rule.weekly(1)
      when 'biweekly'
        schedule.add_recurrence_rule IceCube::Rule.weekly(2)
      when 'monthly'
        schedule.add_recurrence_rule IceCube::Rule.monthly(1)
      when 'annually'
        schedule.add_recurrence_rule IceCube::Rule.yearly(1)
      end
      schedule
    end
  end

  def events(start_date, end_date)
    start_frequency = start_date ? start_date.to_date : Date.today - 1.year
    end_frequency = end_date ? end_date.to_date : Date.today + 1.year
    schedule.occurrences_between(start_frequency, end_frequency)
  end

end
full_calendar.jsvar initialize_calendar;
initialize_calendar = function() {
  $('.calendar').each(function(){
    var calendar = $(this);
    calendar.fullCalendar({
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'month,agendaWeek,agendaDay'
      },
      selectable: true,
      selectHelper: true,
      editable: true,
      eventLimit: true,
      eventSources: [
        '/events.json',
        '/recurring_events.json'
      ],
      select: function(start, end) {
        $.getScript('/events/new', function() {
          $('#event_date_range').val(moment(start).format("MM/DD/YYYY HH:mm") + ' - ' + moment(end).format("MM/DD/YYYY HH:mm"))
          date_range_picker();
          $('.start_hidden').val(moment(start).format('YYYY-MM-DD HH:mm'));
          $('.end_hidden').val(moment(end).format('YYYY-MM-DD HH:mm'));
        });

        calendar.fullCalendar('unselect');
      },

      eventDrop: function(event, delta, revertFunc) {
        event_data = { 
          event: {
            id: event.id,
            start: event.start.format(),
            end: event.end.format()
          }
        };
        $.ajax({
            url: event.update_url,
            data: event_data,
            type: 'PATCH'
        });
      },
      
      eventClick: function(event, jsEvent, view) {
        $.getScript(event.edit_url, function() {
          $('#event_date_range').val(moment(event.start).format("MM/DD/YYYY HH:mm") + ' - ' + moment(event.end).format("MM/DD/YYYY HH:mm"))
          date_range_picker();
          $('.start_hidden').val(moment(event.start).format('YYYY-MM-DD HH:mm'));
          $('.end_hidden').val(moment(event.end).format('YYYY-MM-DD HH:mm'));
        });
      }
    });
  })
};
$(document).on('turbolinks:load', initialize_calendar);
index.json.jbuilderjson.partial! @recurring_events, 
              partial: 'recurring_events/recurring_event', 
              as: :recurring_event
_recurring_event.json.jbuilderevents = recurring_event.events(params[:start], params[:end])
json.array! events do |event|
  json.id "recurring_#{recurring_event.id}"
  json.title recurring_event.title
  json.start event.strftime('%Y-%m-%d')
  json.end (event + 1.day).strftime('%Y-%m-%d')
  json.color recurring_event.color unless recurring_event.color.blank?
  json.allDay true
  json.update_url recurring_event_path(recurring_event, method: :patch)
  json.edit_url edit_recurring_event_path(recurring_event)
end
update.js.erb$('.calendar').fullCalendar('removeEvents', '<%= "recurring_#{@recurring_event.id}" %>');
$('.calendar').fullCalendar(
  'renderEvents', 
  $.parseJSON("<%= j render(@recurring_event, format: :json).html_safe %>"), 
  true
);
$('.modal').modal('hide');


00000000000000000000000000000000?d=mm&f=y&s=64
[email protected] said 14 days ago:

Great Episode! Can you please make an episode where you integrate search for recurring  records? Im using ice_cube and want to create a recurring object and then search for different instances of it based on start_date and end_date lets say. As of now im creating a different object for each recurrence which is highly inefficient, but was having problems searching for the recurrences of the object based on date and filtering and also updating and showing on full calendar. Im sorry if im not very clear. i hope you get an idea about what i want to achieve! Thank you so much again for all your episodes! I've learned a lot watching your episodes. Thanks for doing them and keeping them free!

Olsi 

Login to Comment