The icalendar gem is a useful way to generate iCalendar files for use with various calendar applications. One thing I couldn't find good documentation on, though, is how to use it to create a Webcal link in a Ruby on Rails app, so I figured I'd would go ahead and document that myself.
Before I get started, I'll just mention that all of the code examples in this post are from the demo app, which you can find on Github. Also, the demo app is live, so you can see everything in action.
Webcal
Webcal is what allows a user to click on a link in their browser to subscribe to a calendar in their calendar app.
So, you click on a link in your browser, then a dialog window pops up in your calendar app to subscribe to the calendar:

Then you click Subscribe and, voilà, now that power lunch you have scheduled is in your calendar:

In the future, your calendar app will periodically poll the calendar's URL to check for updates.
Controller
Here's what your controller should look like:
class CalendarsController < ApplicationController
def show
respond_to do |format|
format.ics do
cal = Icalendar::Calendar.new
cal.x_wr_calname = 'Awesome Rails Calendar'
cal.event do |e|
e.dtstart = DateTime.now + 2.hours
e.dtend = DateTime.now + 3.hours
e.summary = 'Power Lunch'
e.description = 'Get together and do big things'
end
cal.publish
render plain: cal.to_ical
end
end
end
end
I'll highlight the important parts:
-
Your controller needs to be unauthenticated, or else the user's calendar app won't be able to access the calendar. So, if your
ApplicationControlleris authenticated, yourCalendarsControllerwill probably need to inherit directly fromActionController::Baseto avoid authentication. -
If your calendar contains sensitive data that should only be available to a specific user, you will need to use a strategy similar to password reset links so that you aren't leaking sensitive data. So, your calendar should be available at a path like
/calendar/u/:some_long_random_string, instead of/calendar/u/:user_id. -
You
respond_totheicsformat. -
You set
cal.x_wr_calnameto specify the default calendar name that will be displayed in the user's calendar app. -
You use
render plain: cal.to_icalto actually render the calendar. In older versions of Rails you would specifytextinstead ofplain.
You can learn about everything else going on in this controller by reading the icalendar gem documentation. It's all standard stuff.
Link
Here's what your subscription link should look like:
<%= link_to 'Subscribe', calendar_url(protocol: :webcal, format: :ics) %>
I'll highlight the important parts:
-
You have to use a full URL, not just a path. The reason for this is the same as for Rails mailers: unlike the browser, the user's calendar app won't know the domain. So, in this example, we're using
calendar_urlinstead ofcalendar_path. -
You specify the
webcalprotocol. This will create a link that starts withwebcal://, instead ofhttp://, which is what tells the browser to hand the link off to the user's calendar app. -
You specify the
icsformat. This will create a link that ends in/calendar.ics, instead of just/calendar, which is what tells Rails to handle the request with theformat.icsblock in the controller.
That's it, you're done!
Just a reminder that you can find the demo app on Github, or see it in action on Heroku.