Resources

Summary

If you want to use the gem instead, then you can ignore downloading FullCalendar and MomentJS. Instead, add the following to the Gemfile.

# Gemfile
gem 'fullcalendar-rails'
gem 'momentjs-rails'

Otherwise, be sure to include the required files in the vendor folder. The rest of the steps are the same regardless of which path you choose.

# application.js
//= require moment
//= require fullcalendar

# application.css
*= require fullcalendar

# full_calendar.js
var 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,
      events: '/events.json',

      select: function(start, end) {
        $.getScript('/events/new', function() {});

        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() {});
      }
    });
  })
};
$(document).on('turbolinks:load', initialize_calendar);

# view/visitors/index.html
<div class='calendar'></div>

# events_controller.rb
class EventsController < ApplicationController
  before_action :set_event, only: [:show, :edit, :update, :destroy]

  def index
    @events = Event.where(start: params[:start]..params[:end])
  end

  def show
  end

  def new
    @event = Event.new
  end

  def edit
  end

  def create
    @event = Event.new(event_params)
    @event.save
  end

  def update
    @event.update(event_params)
  end

  def destroy
    @event.destroy
  end

  private
    def set_event
      @event = Event.find(params[:id])
    end

    def event_params
      params.require(:event).permit(:title, :date_range, :start, :end, :color)
    end
end

# events/_event.json.jbuilder
date_format = event.all_day_event? ? '%Y-%m-%d' : '%Y-%m-%dT%H:%M:%S'

json.id event.id
json.title event.title
json.start event.start.strftime(date_format)
json.end event.end.strftime(date_format)

json.color event.color unless event.color.blank?
json.allDay event.all_day_event? ? true : false

json.update_url event_path(event, method: :patch)
json.edit_url edit_event_path(event)

# events/new.js.erb
$('#remote_container').html('<%= j render "new" %>');
$('#new_event').modal('show');

# events/create.js.erb
$('.calendar').fullCalendar(
  'renderEvent', 
  $.parseJSON("<%=j render(@event, format: :json).html_safe %>"),
  true
);
$('.modal').modal('hide');

# events/edit.js.erb
$('#remote_container').html('<%= j render "edit" %>');
$('#edit_event').modal('show');

# events/update.js.erb
$('.calendar').fullCalendar('removeEvents', [<%= @event.id %>]);
$('.calendar').fullCalendar(
  'renderEvent', 
  $.parseJSON("<%=j render(@event, format: :json).html_safe %>"), 
  true
);
$('.modal').modal('hide');

# events/destroy.js.erb
$('.calendar').fullCalendar('removeEvents', [<%= @event.id %>])
$('.modal').modal('hide');

# events/index.json.jbuilder
json.array! @events do |event|
  date_format = event.all_day_event? ? '%Y-%m-%d' : '%Y-%m-%dT%H:%M:%S'
  json.id event.id
  json.title event.title
  json.start event.start.strftime(date_format)
  json.end event.end.strftime(date_format)
  json.color event.color unless event.color.blank?
  json.allDay event.all_day_event? ? true : false
  json.update_url event_path(event, method: :patch)
  json.edit_url edit_event_path(event)
end