Fetching and caching Google Calendar data in Rails
Recently we had a requirement to show Google Calendar data for a client on a Rails intranet project. The requirements were a bit outside what’s offered by the embedded iFrame option so we needed a better solution to retrieve Google calendar data.
Options for getting data from Google Calendar ¶
The simplest option is just to use the iFrame that Google provide that is accessible from your Google Calendar under Settings > Calendars > Name of your Calendar > Embed This Calendar. You don’t really get to customise this though so what you see is what you get
If you want the raw data so you can do things with it Google publish the gdata-ruby-util Ruby library which provides an interface into Google’s Data APIs. This is a very useful gem, providing full access to lots of data across Google services. From a Ruby perspective it seemed like you need to write a lot of code for a simple API call.
Better for our requirments was the GCal4Ruby gem that provides a clean interface to Google Calendar data. It works for both Google and Hosted Accounts and with just six lines of ruby you can get event data for a particular calendar:
service = GCal4Ruby::Service.new
service.authenticate("USERNAME", "PASSWORD")
cal = GCal4Ruby::Calendar.find(
service,
'YOUR_CALENDAR',
{:scope => :first}
)
events = GCal4Ruby::Event.find(
cal,
"",
{
:range => {:start => Time.parse("08/04/2000"),
:end => Time.parse("09/04/2010")}
}
)
Once you’ve got the data you can iterate over it as you want
for event in events
#do stuff here
puts event.title
end
Caching ¶
The API call takes a while to come back so we don’t really want the user experience to be impacted by slow load times. We can use Rails caching to store the response and only fetch it when we need to. We put this into a rake task so that we could call it using a cron script to keep the calendar up to date
task :gcal_update => :environment do
Rails.cache.delete('gcal_events')
Rails.cache.fetch('gcal_events') {
gservice = GCal4Ruby::Service.new
gservice.authenticate("USERNAME", "PASSWORD")
calendar = GCal4Ruby::Calendar.find(gservice, 'your calendar', {:scope => :first})
events = GCal4Ruby::Event.find(calendar, "", {
:range => {:start => Time.now.beginning_of_day, :end => Time.now.advance(:days => 7)},
:singleevents => true,
:max_results => 1000,
:sortorder => "ascending" })
upcoming_events = {}
# We're saving the next 7 days of events
days = Date.today..Date.today.advance(:days => 7)
# initialize the hash
days.each{ |day| upcoming_events["#{day.to_s}"] = []
}
events.each do |e|
# should find out if its an all day event or a recurring event.
event = Hash.from_xml(e.to_xml)["entry"]
days.each do |day|
current_event = {}
if (event["when"]["startTime"].to_date <= day) and (event["when"]["endTime"].to_date >= day)
# save useful data into a hash
current_event["all_day"] ||= event["when"]["startTime"].to_time.to_date < event["when"]["endTime"].to_time.to_date ? true : false
current_event["title"] = event["title"]
current_event["uri"] = event["link"][0]["href"]
current_event["time"] = event["when"]["startTime"].to_time.strftime('%H:%M') if event["when"]["startTime"].to_date == event["when"]["endTime"].to_date
upcoming_events["#{day.to_s}"].push(current_event)
end
end
end
upcoming_events
}
end
Showing the calendar ¶
Now in our controller we have an easy way to get the latest calendar data and we can then loop over it in our view
@calendar = Rails.cache.read('gcal_events')
Tags
Can you help make this article better? You can edit it here and send me a pull request.
See Also
-
All magic comes with a price
Leaning on abstractions is powerful but you should know what it means