The project is in a healthy, maintained state
Adds `index as: :calendar` — a month-grid index style that buckets resources by a date attribute or custom scope and yields each day cell.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 3.5, < 5.0
>= 1.4, < 3.0
>= 7.0
 Project Readme

activeadmin_calendar

CI Coverage Ruby

Adds index as: :calendar to ActiveAdmin — renders the resource list as a month grid with one cell per day. The index block is yielded (date, records_for_that_day).

Works with ActiveAdmin 3.5+ and 4.x.

ActiveAdmin 4

Payments calendar on AA 4

ActiveAdmin 3

Payments calendar on AA 3.5

Install

# Gemfile
gem "activeadmin_calendar"

For Sprockets (AA 3):

/* app/assets/stylesheets/active_admin.scss */
@import "activeadmin_calendar";

Propshaft / Tailwind (AA 4) picks the bundled CSS up automatically.

Usage

Single-date events — group_by:

One SQL query per visible month, rows bucketed in Ruby.

ActiveAdmin.register Payment do
  config.paginate = false
  filter :card_type, as: :select, collection: Payment::CARD_TYPES

  index as: :calendar, group_by: :paid_at do |date, payments|
    by_card = payments.group_by(&:card_type)
                      .transform_values { |ps| ps.sum(&:amount) }
    ul do
      by_card.each { |c, sum| li "#{c.upcase}: #{number_to_currency(sum)}" }
      total = by_card.values.sum
      li { strong "Total: #{number_to_currency(total)}" } unless total.zero?
    end
  end
end

Range / fan-out events — group_by_scope:

One row appears in every day in its active range. Use a custom scope:

ActiveAdmin 4

Bookings calendar — fan-out on AA 4

ActiveAdmin 3

Bookings calendar — fan-out on AA 3.5

class Booking < ApplicationRecord
  scope :active_on, ->(date) { where("check_in <= ? AND check_out > ?", date, date) }
end

ActiveAdmin.register Booking do
  filter :room_number
  filter :guest_name_cont, label: "Guest name contains"

  index as: :calendar, group_by_scope: :active_on do |date, bookings|
    ul do
      bookings.sort_by(&:room_number).each do |b|
        first, last = b.check_in == date, b.check_out - 1.day == date
        marker = first && last ? "•" : first ? "→" : last ? "←" : "·"
        li { text_node "#{marker} ##{b.room_number} #{b.guest_name}" }
      end
    end
  end
end

May 18 → 21 booking shows on 18 (), 19 (·), 20 ().

Options

Option Effect
group_by: (Symbol) Bucket by a date/datetime column. 1 SQL per month (prefetched).
group_by_scope: (Symbol) Call Model.scope(date) per cell — for ranges, joins, or any bucket logic that simple where(col = date) can't express. N SQL per month (one per visible day).

URL params ?year=2026&month=5 drive the visible month. Today / Previous / Next links are rendered automatically and preserve current filter params.

Ransack filters apply transparently — the gem buckets the already-scoped collection. ?q[card_type_eq]=visa narrows what's shown in each cell.

Compatibility

AA Status
4.0.0.beta22
3.5

License

MIT