Sử dụng gem fullcalendar trong ứng dụng rails

Giới thiệu thư viện Full Calendar Full Calendar là thư viện mã nguồn mở. Đây là bộ thư viện được xây dựng bằng javascript + jquery, với thiết kế đẹp mắt, đầy đủ các tính năng cơ bản cho một Calendar và có thể hiển thị các events trên calendar, giúp quản lý công việc và theo dõi tiến độ làm việc một cách dễ dàng hơn. gem "fullcalendar-rails" Đây là một gem giúp chúng ta có thể dùng jQuery FullCalendar plugin, mà không cần phải download and install FullCalendar trong assets.

Để cài đặt và sử dụng Đầu tiên chúng ta tạo 1 ứng dụng rails.

rails new demo_fullcalendar 

Chúng ta sẽ sử dụng các gem

gem "fullcalendar-rails"
gem "momentjs-rails"
gem "bootstrap-sass"

Trong file app/assets/javascripts/application.js chúng ta thêm

//= require moment
//= require fullcalendar
//= require bootstrap-sprockets

Trong file app/assets/stylesheets/application.scss chúng ta thêm *= require fullcalendar

@import "bootstrap-sprockets";
@import "bootstrap";

Chúng ta tạo một trang static_pages.

rails g controller StaticPages index 

Trong file static_pages/index.html.erb (page_sẽ show calendar) chúng ta thêm:

<div class="calendar"></div>

Chúng ta tạo 1 model event

rails g model events title:string start_date:datetime end_date:datetime color:string 
rails g controller events

File routes

Rails.application.routes.draw do
  root 'static_pages#index'
  resources :events
end

Chúng ta tạo 1 file app/assets/javascripts/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',

      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).ready(function(){
  initialize_calendar();
});

Các phương thức cơ bản trong Full Calendar selectable: cho phép người dùng có thể chọn và di chuyển các event trong calendar, có 2 option là true hoặc false editable: cho phép người dùng chỉnh sửa trong calendar weekends: nếu giá trị là true thì sẽ hiển thị ngày cuối tuần, và ngược lại. url: cho phép hiển thị định dạng url droppable: cho phép người dùng thả các event vào trong calendar eventLimit: giới hạn số event trong 1 calendar listView: hiển thị các event theo dạng listView updateEvent: cập nhật lại các event trong calendar renderEvent: thêm event vào trong calendar remove: xóa event khỏi calendar Và còn nhiều thuộc tính và phương thức khác, để biết thêm chi tiết, bạn đọc có thể xem tại đây

Bây giờ chúng ta chạy server thì có thể thấy giao diện của fullcalendar

Bước tiếp theo chúng ta sẽ tạo event trong data và show trên full-calendar. Trong file event.rb

class Event < ApplicationRecord
  validates :title, presence: true
  validates :start_date, presence: true
  validates :end_date, presence: true
end

Trong file events_controller.rb

class EventsController < ApplicationController
  before_action :load_event, only: [:show, :edit, :update, :destroy]

  def index
        @events = Event.all
  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_attributes event_params
  end

  def destroy
    @event.destroy
  end

  private
  def load_event
    @event = Event.find_by id: params[:id]
  end

  def event_params
    params.require(:event).permit(:title, :start_date, :end_date, :color)
  end
end

Chúng ta sẽ tạo 1 số file file _new.html.erb

<div class="modal fade" id="new_event" role="dialog">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal">&times;</button>
        <h4 class="modal-title">Create New Event</h4>
      </div>
      <div class="modal-body">
        <%= render 'form', event: @event %>
      </div>
    </div>
  </div>
</div>

file _event.json.jbuilder

date_format ='%Y-%m-%d'

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

json.color event.color unless event.color.blank?

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

file _form.html.erb

<%= form_for @event, remote: true do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title, class:"form-control" %>
  <%= f.label :start_date %>
  <%= f.date_field :start_date, class:"form-control"  %>
  <%= f.label :end_date %>
  <%= f.date_field :end_date, class:"form-control"  %>
  <%= f.label :color %>
  <%= f.select :color, [['Black','black'], ['Green','green'], ['Red','red']],
    {}, {class: "form-control"} %>
  <%= f.button :submit, class:"btn btn-primary" %>
  <%= link_to 'Delete',
              event,
              method: :delete,
              class: 'btn btn-danger',
              data: { confirm: 'Are you sure?' },
              remote: true unless @event.new_record? %>
<% end %>

file _edit.html.erb

<div class="modal fade" id="edit_event">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal"
          aria-hidden="true">&times;</button>
        <h4 class="modal-title">Edit Event</h4>
      </div>
      <div class="modal-body">
        <%= render 'form', event: @event %>
      </div>
    </div>
  </div>
</div>

file create.js.erb

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

file destroy.js.erb

$('.calendar').fullCalendar('removeEvents', [<%= @event.id %>])
$('.modal').modal('hide');

file edit.js.erb

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

file index.json.jbuilder

json.array! @events do |event|
  date_format = '%Y-%m-%d'
  json.id event.id
  json.title event.title
  json.start event.start_date.strftime(date_format)
  json.end event.end_date.strftime(date_format)
  json.color event.color unless event.color.blank?
  json.allDay true
  json.update_url event_path(event, method: :patch)
  json.edit_url edit_event_path(event)
end

file new.js.erb

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

file update.js.erb

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

Trong file application.html.erb chúng ta thêm <div id='remote_container'></div> để show modal event

kết quả

Click vào ngày tạo event Trang index calendar Click vao event update Event

Kết luận

Như vậy, với bộ thư viện Full Calendar, bạn có thể tạo ra cho mình một bộ calendar tuyệt đẹp với nhiều tính năng mà không cần thiết phải sử dụng quá nhiều dòng lệnh để xây dựng lại từ đầu