iCalendar and webcal subscription feed in Rails

I’ve been working on a project where I needed to have an iCalendar webcal subscription link. Webcal is a protocol that is recognized by applications that support the .ics iCal format (iCal, Outlook, etc) to subscribe to a feed of events. It’s essentially a RSS feed for calendaring applications. Thanks to the awesome iCalendar gem, adding this feature to my Rails app was pretty much a breeze. Here’s how to do it.

The first step is to install the gem and set it up in your Rails app.

sudo gem install icalendar

Add this to your environment.rb file:

config.gem 'icalendar'

Now that you have the gem setup, you just need to add the code to your controller. Say we have a method called ‘feed’ that generates the webcal feed for our events. We could have something setup like this:

def feed @user = User.find_by_feed(params[:feed]) @events = Events.find_by_user(@user) respond_to do |format| if @user.valid? format.ics { render :text => self.generate_ical }
else format.ics { render :nothing => true, :status => :forbidden } end end end

Pretty simple so far. You’ll just want to create a new responder for the webcal and set to render text. That part is important. Next we have the method that actually generates the webcal feed, which uses the iCalendar gem.

def generate_ical cal = Icalendar::Calendar.new cal.custom_property("METHOD","PUBLISH")
@events.each do |e| event = Icalendar::Event.new event.start = e.start.strftime("%Y%m%dT%H%M%S") event.end = e.end.strftime("%Y%m%dT%H%M%S") event.summary = e.summary event.description = e.summary event.url = "http://yourwebsite.com" event.add_comment("More info at http://yourwebsite.com") cal.add event end headers['Content-Type'] = "text/calendar; charset=UTF-8" cal.publish cal.to_ical end

I implemented many of the available fields here, but you can check the gem’s docs for a full list of stuff you can add to an event. You can event setup things like alarms and todos.

It’s important here to set the method to publish, to set the content-type as a calendar format and to publish the calendar. Then, you need to return it in, basically, an iCal string to the feed method, which will actually serve it.

Now, to link up your fancy webcal feed, just add this in a view:

< %= link_to "iCal", {:controller => 'events', :action => 'feed', :feed => current_user.feed, :format => :ics, :only_path => false, :protocol => "webcal"} %>

This is really just using a link helper, but it’s important that you make sure the link is in the format: webcal://yourwebsite.com/events.ics. Of course, the helper can do this. By passing it a format parameter in the options hash you’ll get a .ics. To make sure the link is a webcal link, it’s important to pass the :only_path => false parameter first and then passing the helper the protocol parameter.

And that’s it. It’s pretty simple. Hope this helps you out. It turned out to be a really awesome feature for my app.

Update: If you’re running ruby 1.9.x, the iCalendar gem will not work properly. It seems to output invalid .ics files because it treats the strings as arrays. I’m not sure why, but I couldn’t find a workaround so I moved instead to the much newer ri_cal gem.

About Logan Leger

Logan Leger is a native Louisianaian and technologist. He is currently a computer engineering student at LSU and is employed there in the ITS department. He also works with Noteflood and NewAperio, his own startup he founded with classmates from LSMSA. You can read more about him here.
This entry was posted in Code and tagged ical, icalendar, rails, ruby on rails, webcal. Bookmark the permalink.

13 Responses to iCalendar and webcal subscription feed in Rails

  1. Sean says:

    You mention in an update at the end that you’ve switched to ri_cal. I’ve done the same. Have you been able to get a webcal subscribe-able version working? Care to publish what changes you made in your code to make it work with ri_cal?

  2. Logan Leger says:

    Sean,

    Here’s my new generate_ical method:

    def generate_ical mon = Time.now.monday @week = 0.upto(13) RiCal.Calendar do |ical| ical.add_x_property 'X-WR-CALNAME', 'Calendar Name' @events.each do |e| ical.event do |event| event.dtstart = e.start.strftime("%Y%m%dT%H%M%S") event.dtend = e.end.strftime("%Y%m%dT%H%M%S") event.summary = e.summary event.description = e.summary event.url = "http://yourwebsite.com"
    event.add_comment("More info at http://yourwebsite.com") end end end.export
    end

  3. keith says:

    Very much enjoying experimenting with ri_cal. Thanks for this quick tip. I don’t think Rails 3 plays very nice with this totally as I’m getting NoMethodError on ‘feed’ but I’ll work through it. Thanks!

  4. Yuval says:

    I’ve found that a colon is being appended to my calendar name when I try to subscribe to it in iCal. Have you experienced this?

  5. Daniel says:

    Hi

    I’m trying to get this working, and so far it’s worked pretty well for subscribing. But it seems to be read only :’(

    Do you know of any examples where there is a complete action that can be fired from the client for a two way sync?

    • Logan Leger says:

      Never done that before. Let me know if you figure it out.

    • Burton Rhodes says:

      I’m pretty sure that’s impossible due to the nature of what a webcal:// feed is. It’s exactly that, a feed – not a sync. Essentially the only thing that is transferred to the client is a .ics file that is interpretted as the feed. There is no two way communication. You would have to write a “sync” backend which can get pretty involved.

  6. Phillip says:

    @Keith – I’m getting the NoMethodError as well. Did you resolve this? I’m going to step away and revisit in the morning. Sometimes that does wonders! Phillip Rheem Water Heaters – rheemwaterheaters.net

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>