In this article we will show you how to build a calendar in Ruby on Rails. Fortunately it is relatively easy to do so. The calendar that we build will be extendable, meaning you can add your own functionality as needed, so lets get started.

The first thing we need to do is create a calendar.rb file in our lib folder. This file will hold a class that contains the core calendar functionality. Create this new file and add in the code listed below.


class Calendar <, :date, :callback)
    HEADER = %w[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]
    START_DAY = :sunday
    delegate :content_tag, to: :view
    def table
      content_tag :table, class: "calendar table table-bordered table-striped" do
        header + week_rows
    def header
      content_tag :tr do { |day| content_tag :th, day }.join.html_safe
    def week_rows do |week|
        content_tag :tr do
 { |day| day_cell(day) }.join.html_safe
    def day_cell(day)
      content_tag :td, view.capture(day, &callback), class: day_classes(day)
    def day_classes(day)
      classes = []
      classes << "today" if day ==
      classes << "not-month" if day.month != date.month
      classes.empty? ? nil : classes.join(" ")
    def weeks
      first = date.beginning_of_month.beginning_of_week(START_DAY)
      last = date.end_of_month.end_of_week(START_DAY)

The next thing we need to do is modify our application config to auto load .rb files in the lib folder. By default rails doesn't do this. Modify your application config so that it has the line listed below. Be careful not to overwrite the model name for your application as well as other parameters that may be set.


require File.expand_path('../boot', __FILE__)

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env)

module CalendarExample
  class Application < Rails::Application
    config.autoload_paths += %W(#{config.root}/lib)
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Set default to the specified zone and make Active Record auto-convert to this zone.
    # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
    # config.time_zone = 'Central Time (US & Canada)'

    # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
    # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
    # config.i18n.default_locale = :de

The next thing we need to do is include bootstrap to give our calendar a bit of style. Open up your application layout and modify it so that it looks like the code listed below. We load bootstrap from Yandex's CDN for simplicity. Remember, if you want to use your own stylesheets for the calendar, you don't have to use bootstrap. It's used here simply to improve the visual quality.


<!DOCTYPE html>
  <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
  <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
  <%= stylesheet_link_tag "", media: "all" %>
  <%= javascript_include_tag "" %>
  <%= csrf_meta_tags %>
<div class="container">
<%= yield %>


The next thing we need to do is create a controller. Run the command below to create a calendar controller.

Terminal Commands:

rails g controller Calendar show

Great! Now we need to update our routes. Open up your routes file and modify it so that it looks like the code listed below, once again being careful not to overwrite your existing application's name.


CalendarExample::Application.routes.draw do
  resource :calendar, only: [:show], controller: :calendar
  root to: "calendar#show"

Now lets create a helper method that will allow us to easily render the calendar. Open up your calendar helper file and modify it so that it looks like the code listed below.


module CalendarHelper
  def calendar(date =, &block), date, block).table

Now open up your calendar controller and modify it so that it looks like the code listed below. This code sets up the date that will be used by the calendar.


class CalendarController < ApplicationController
  def show
    @date = params[:date] ? Date.parse(params[:date]) :

Great, now finally, open up the show view for the calendar controller and add in the following code.


<div class="row">
  <div class="col-md-12 text-center">
    <div class="well controls">
      <%= link_to calendar_path(date: @date - 1.month), class: "btn btn-default" do %>
        <i class="glyphicon glyphicon-backward"></i>
      <% end %>
      <%= "#{@date.strftime("%B")} #{@date.year}" %>
      <%= link_to calendar_path(date: @date + 1.month), class: "btn btn-default" do %>
        <i class="glyphicon glyphicon-forward"></i>
      <% end %>
<div class="row">
  <div class="col-md-12">
    <%= calendar @date do |date| %>
      <%= %>  
    <% end %>

Of importance to note is the last 6 lines. This actually renders the calendar using the Calendar helper method. The helper method is a block that loops through each day. What if you wanted to add events? That's easy! Assuming your event model is called event, you'd add this code to your calendar controller:

@events_by_date = Event.group_by(&:date)

Then you'd modify your calendar block so that it looks something like the code listed below.

<%= calendar @date do |date| %>
  <%= %>
  <% if @events_by_date[date] %>
      <% @events_by_date[date].each do |event| %>
        <li><%= link_to, event %></li>
      <% end %>
  <% end %>
<% end %>

That's it! That's all there is to it! Thanks for reading!