What we're listening to:
Jared

Thrice:
Beggars
Jeff

Paper Route:
Absence

Event Calendar Rails Plugin

July 23rd, 2009

For a recent project we needed to show events on a calendar. The existing Rails plugins we tried didn’t allow us to satisfactorily show multiple, overlapping events across calendar days and rows.

I found the same complaint here and began to adapt it to our needs.

I’ve extracted the result and put it on github in the hopes that others might find it useful and/or add improvements.

http://github.com/elevation/event_calendar

The above link has more details, as well as how to install and use the plugin.

Here’s the 1000 word screenshot:

Event Calendar Screenshot

Using the use_all_day option:

Event Calendar using all day option

PLEASE:

Thanks and enjoy!

79 Responses to “Event Calendar Rails Plugin”

  1. Nice to see my code adapted as a plugin. Great work!

    Hopefully should be very useful to rails developers. :)

  2. ok, i do have a question this time. I have followed your defaults and created an event scaffold but how would i display the events and the calendar on the same page?

  3. It looks fabulous and thank you for spending the time to create this plugin, but is there any chance that you could provide a sample application?

  4. @kevin

    I broke out finding events into it’s own method, so you can call it separately if you need/want to.

    In your controller, instead of the single Event.event_strips_for_month, make these three calls:

    start_d, end_d = Event.get_start_and_end_dates(@shown_month)
    @events = Event.events_for_date_range(start_d, end_d)
    @event_strips = Event.create_event_strips(start_d, end_d, @events)
    

    Then in your view you can use that @events instance variable to list the events.

    (replace ‘Event’ with your model name of course)

    @Jeff

    Putting up a sample app is on my list of things to do. I’ll update the post/github when I have something.

  5. We are new to Rails and just found your plugin. It looks awesome, but when trying to run the install nothing happens. It almost immediately goes back to a prompt, when we run the generate command it says “Couldn’t find ‘event_calendar’ generator. Any help?

  6. @Andre
    Interesting… so this isn’t working within your rails project?

    script/plugin install git://github.com/elevation/event_calendar.git
    

    Do you have git installed on your system? You could also try downloading the zip/tar file from github by clicking the ‘Download’ button, rename the extracted folder event_calendar, and put it in your vendor/plugins directory. You should then be able to run the event_calendar generator. Hope that helps.

  7. I’m trying to use the plugin and I’m following the example on github and there’s a problem when calling ‘event_strips_for_month’ because that’s not defined in Event model.

    What should that method to? I will write it, but I need to know what is it supposed to do.

    Thanks in advance

    Diego

  8. I have a new problem now:

    NameError in CalendarController#index

    undefined local variable or method `has_event_calendar’ for #

  9. @Diego
    Are you putting the ‘has_event_calendar’ method call in your event model, or do you have it in the controller? It should be in your model…

  10. @month = params[:month].to_i
    @year = params[:year].to_i

    @shown_month = Date.civil(@year, @month)
    start_d, end_d = Event.get_start_and_end_dates(@shown_month)
    @events = Event.events_for_date_range(start_d, end_d)
    @event_strips = Event.create_event_strips(start_d, end_d, @events)

    this is my controller. I am getting a problem with Date.civil.
    The error is

    ArgumentError (invalid date):
    C:/Ruby/lib/ruby/1.8/date.rb:727:in `civil’
    app/controllers/events_controller.rb:54:in `monthly

    Regards,
    H

  11. @hs

    What are your @month and @year variables when you get that error? They should be integers like 8 and 2009. So: Date.civil(2009, 8) => Sat, 01 Aug 2009.

    In my example, I default the params to Time.now.month and Time.now.year in the routes file:

    map.calendar "/calendar/:year/:month", :controller => "calendar", :action => "index", :year => Time.now.year, :month => Time.now.month

  12. I’m sorry to bug you with such a simple question but I am new to ruby and was wondering if you could help. I only want to show events that belong the the currently logged in user (current_user). How would I change this:

    def event_calendar
    calendar event_calendar_options do |event|
    #{h(event.name)}
    end
    end

    Thanks in advance for your help

  13. I fixed it. I just changed:

    In my calendar_controller:

    @event_strips = Events.event_strips_for_month(@shown_month)

    to

    @event_strips = current_user.events.event_strips_for_month(@shown_month)

  14. I’ve been playing with this for the past couple of days and I’m very pleased.

    @Jeff Schuil: Have you thought about the design of the calendar grid itself? Currently it’s designed
    to only use 85px or 120px as the cell width (to fill up the background with either 85_bg.gif or 120_bg.gif).

    However, if you want a table width of 100%, no background image will work. Ideally you want to fill those blank spaces with plain css (borders).
    Any thoughts?

  15. I am getting save error as @hs

    ArgumentError (invalid date)

    I checked the year and month like you had suggested and:
    My month is 0.
    my year is 0.

    If I set these variables in my controller. Then it works… but my next and prev. buttons do not.

    It seems that my variables are not initialized by the route.

    I’m hoping its something simple..(fingers crossed)

  16. Ok so I discovered my problem!

    In routes.

    I had added the “map.calendar….” route below the default routes.

    Move the “map.calendar” route above the default routes.

  17. @Jermaine

    While you can set the width to be whatever you want (by changing a setting and creating a new bg image), I agree it would be ideal if the calendar could resize dynamically. (ie with a browser window resize)

    Right now each ‘event strip’ is a div placed within a single table cell that stretches across all the days of the week. The background image just gives the appearance of multiple cells. It could be re-written to produce HTML where each event strip is a table cell that spans the required number of day cells. The cells would then change width dynamically as the width of the table changed.

    Also, instead of repeating bg images for the grid, perhaps it could use another table, that has position absolute, and is just there to give the cell/day borders.

    It’s hard to describe in a comment, but those are my quick thoughts. This is on my list of things I’d like, so let me know how it goes and I’ll update the plugin if we get something working.

  18. Hi,

    I’m having a problem with the plugin. Whenever I make an event on a Friday later than 4PM(start_at 17:00:00) or so, it extends onto Saturday. I’m not sure how to resolve this, but I didn’t notice this before. I set my time zone to Pacific time in my environment.rb, but the server time is different. Could this be a problem?

    Thanks.

  19. I really like this calendar. Thank you. I see a couple of issues. When my end date is past 8:00 PM on *Friday*, the stripe spills over to Saturday. Oddly, this is only on Friday. I originally thought it was a timezone issue since I’m using US/Eastern. But having it happen on Friday is a real puzzle.

    Also for October 2009, I get full row of empty cells at the bottom. I guess that is because the 31st falls on Saturday.

    Thanks, Really like it!

  20. @Jeff and @Tom

    You’re correct that it was a timezone issue. The bug only came up when the event’s end date was close to the end of the week (Friday afternoon/nights depending on the time change.) Nice find. It should now be fixed.

    I also removed the extra calendar row that was showing for the month of October. This one came up when the last day of the month was also the last day of the week (Saturday).

    Also, feel free to create an issue on github for these types of bugs, instead of a blog comment. I’ll start creating them there if they are reported here…

    Thanks, and I’m glad you like the plugin!

  21. Not sure why but all events show up in calendar to day early.

    i.e event datetime = 2009-10-05 00:00:00 shows up on the calendar on the 3rd.

    also is there a way to set the end_at to the same as the start_at time.
    I only need the date not the time.

    Thanks

  22. @Larry

    Not sure why events would show up early for you either. Maybe this is another timezone problem? I see you opened a github issue, I’ll ask for more info there…

    As for setting end_at to be the same as the start_at, you could easily do this in your event model.

    def end_at
      start_at
    end

    I guess this means you only want to display single day events?

    If you’re just trying to get rid of the event’s time, leaving only the date, then you should be able to replace start_at and end_at’s datetime data type with date. (ie in your event migration)

    Or just don’t display the time information.

    Another option, if you want a mix of dates and datetimes, is to add an ‘all day’ checkbox when creating an event.

  23. Just wanted to follow up with the Friday night spill over timezone issue. The updated fixed it. Thanks.

  24. This calendar is great. I’m trying to figure out how to turn the view into a popup, hopefully it won’t be too hard.

  25. Hi,

    Is there a way to change the calendar so the event title spans in the same cell, but moved down instead of having text cut off? Like “A really long title” would read as “A really lo” on the calendar.

    Also, is there a way to change the colors based on different event types? If an event was type a, is there a way to set it to a different color then type b?

    Thanks again for this wonderful plugin!

  26. Does this require rails 2.x? I’m running trying to use it on a legacy site that is rails 1.2 and I get this error when trying to generate the calendar:

    You have a nil object when you didn’t expect it! (NoMethodError)

  27. @Jeff

    To have the event name text wrap within the calendar day, instead of cutting it off, you’re going to have to make a change to the plugin.

    In the plugin directory open:
    event_calendar/lib/event_calendar/calendar_helper.rb
    and look for the ‘event_content’ method. You’ll see the height of that div is being set. You can remove setting the height, but you’ll probably get some overlapping if you have multiple events on the same day, with long event names. Let me know if you get it working, and I’ll add it as an option to the plugin.

    For the second question, just override the color method on your event model.

    def color
    # color logic based on event type
    # or maybe associated calendar?, ie
    # self.calendar.color
    end

  28. @Clark

    I haven’t tried it on earlier versions of Rails, but based on your error I think it does require 2.x. You may only have to make a few changes to get it working on 1.x though…

  29. @Jeff

    Thanks. I upgraded the site to Rails 2.3 and it works well now.

  30. Does this require some other gem? Your calls to Time.zone (e.g. Time.zone.now.year) don’t work for me as there is no such method on Time. I’ve confirmed this with IRB in Ruby 1.8.7

    I have it working now by removing the call to zone but seems like I must have something wrong

  31. @Clark

    Time.zone was introduced in Rails 2.1. Try it out in the rails console, instead of just IRB.

    http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html#M001520

  32. No good on Rails 2.3.2. See output from rails console:
    Loading development environment (Rails 2.3.2)

    *******************************************************************
    * config.breakpoint_server has been deprecated and has no effect. *
    *******************************************************************

    Time.zone.now.year
    NoMethodError: You have a nil object when you didn’t expect it!
    The error occurred while evaluating nil.now
    from (irb):1
    Time.zone
    => nil
    Time.now
    => Fri Oct 02 14:16:19 -0400 2009

  33. @Clark

    I think I know what’s happening. When you upgraded Rails, you now need to set your time_zone in environment.rb

    # Run “rake -D time” for a list of tasks for finding time zone names.
    config.time_zone = ‘UTC’

  34. Bingo. Thanks!

  35. I am getting an argument error in my controller that says invalid date. Can you help with that?

    Thanks

  36. @Brandon

    Sounds like the same problem @TS had in a comment above:

    “Move the “map.calendar” route above the default routes.”

  37. I am receiving the follwing NoMethodError in Calendar#index

    “undefined method `name’ for Thu, 01 Oct 2009:Date”

    Thanks in advance Jeff for being active on this post.

    -Leo

  38. @Leo

    I think I need more info. Are you following the example in the README? It should be calling ‘name’ on an Event type object, not a Date. Look for where it’s calling event.name (in a helper or view) and see why you have a Date.

  39. Thanks Jeff,

    Found out I hadn’t erased the has_calendar plugin.

    -Leo

  40. Jeff,

    I am trying to put the event calendar in a view other than the calendar view but I’m getting the following error:

    NoMethodError in Store#calendar

    Showing app/views/store/calendar.html.erb where line #3 raised:

    You have a nil object when you didn’t expect it!
    The error occurred while evaluating nil.strftime
    Extracted source (around line #3):

    1: ‘top’ %>
    2:
    3:
    4: ‘event’, :action => ‘new’ %>
    5:

    It seems like I am not able to pull the events from here. Any thoughts on how I could do this?

    Thanks again

  41. Nevermind.

  42. What would be the easiest way to auto populate my calendar with three blank events each day?

    Thanks in advance

    Leo

  43. Hi,

    I’m running Rails 2.3.4 on Passenger and the app is failing to start since including the plugin and generated Event model:

    Error message:
    no such file to load — application.rb (MissingSourceFile)
    Exception class:
    PhusionPassenger::UnknownError

    And I know that since a few releases ago, application.rb is called application_controller.rb; I can’t find any references to application.rb in the code. Any thoughts?

  44. @Avishai

    I can’t think of a reason why you’re getting that error. It seems to be ok in a fresh Rails 2.3.4 project. I just ran these steps and got a working calendar.

    1. rails test_cal
    2. cd test_cal
    3. script/plugin install git://github.com/elevation/event_calendar.git
    4. script/generate event_calendar
    5. rake db:migrate
    6. script/server

    I get a calendar at http://localhost:3000/calendar. I also added an event in the db and it came up as well without an error.

    Must be a conflict with your current application? Some people have had problems when they forgot to remove the original Calendar Helper plugin.

  45. Hello,

    I am testing the plugin and I was wondering if it is possible, in the :link_to_day_action, to have a restful route like new_user_event(current_user) if I have a calendar by user.

    Thanks
    Nicolas

  46. @Nicolas

    Override the day_link helper method. For example,
    In helpers/calendar_helper.rb

    def day_link(text, date, day_action)
      link_to(text, new_user_event_path(current_user), :class => 'day_link')
    end
    
  47. I can’t push to github through my work proxy, but i found a bug – If you have more than 4 events and one of the later ones spans multiple weeks, it is displayed outside of (below) the event strip for that week.

    to fix it in def event_row the first few lines should read

    
      num_events = 0
      event_counter = 0
      content.each do |strip|
        event_counter += 1
        if !strip.blank?
          num_events = event_counter
        end
      end

    Cheers for the cool plugin.

  48. @Anko

    Good catch! I just updated the plugin with your fix. Thanks.

  49. Hi Jeff,

    I was trying to use this in a existing project with several event like models. Is it possible to alias the start_at and end_at columns without refacoring the plugin or my whole project? i.e. the my existing models use start_date and end_date.

    I’m guessing that the answer is currently no, :( but here’s hoping. :)

    Sean.

  50. @Sean

    You could try using the rails helper method ‘alias_attribute’ in your model.

    alias_attribute :start_at, :start_date
    alias_attribute :end_at, :end_date

    If nothing else, you could create start_at/end_at getters and setters to wrap your attributes.

  51. What do you think about add to default generation next rows
    routes.rb
    map.event '/event/:id', :controller => 'calendar', :action => 'show_event'

    #in CalendarHelper override method

    def event_calendar
      calendar event_calendar_opts do |event|
        link_to_remote(content_tag(:div, h(event.name)),
          :url =>  event_path(event),
          :title => "#{h(event.name)}: #{event.start_at} to #{event.end_at}",
          :href => event_path(event)
        )
      end
    end
  52. And I think need use mb_chars for correctly strip day names in multilingual projects

    day_names.each do |d|
      unless d[options[:abbrev]].eql? d
        cal < < %(#{d.mb_chars[options[:abbrev]]})
      else
        cal << %(#{d.mb_chars[options[:abbrev]]})
      end
    end
    
  53. Thanks the quick response Jeff. I did try wrapping the start_date and end_date in getters and setters but unfortunately ran that wouldn’t work with the SQL in event_calendar.rb.

    In the end I just did a project find and replace for start_at and end_at and it so quick to do that I was kicking myself for not trying it earlier!

    Only problem I have now is that I’ve effectively forked the plugin. Oh, well.

    If I think of a more elegant solution I’ll pass it back as a patch.

  54. [...] Event Calendar rails plugin (see: post & github) we created a few months back has been working great and, thanks to all the feedback, [...]

  55. Excellent! Thanks a lot, the calendar looks great, and was extremely easy to implement.

    Couple of issues:

    -do you know why IE 8 in both modes (compatibility and regular) misaligns the rows with day numbers? They are off by a couple of pixels to the right. Is this an easy CSS fix?
    -is it just my implementation or the events that wrap down to the next row do not have one hover effect for all days in the event? The part in one row “hovers” independently of the part in the following row.

    I can live with both of those (unless my client checks it in IE 8, then I’m screwed… LOL) so again, big THANKS, but awaiting your input. Later.

  56. @Chris K

    I just checked it in IE8, and everything looks good. I’m guessing you have a CSS style adding some extra padding. Try displaying with just the event_calendar.css stylesheet and see if it looks ok. If it does, then check your other stylesheets, particularly those that set styles for td elements.

    As for the hover effect working across calendar rows… This is done in the javascript method event_select, with the default implementation using prototype for selecting elements. Make sure you have both the prototype and event_calendar.js files included in your page. (There is also a jQuery version of event_select, if that is what you prefer.)

  57. Aaahhh… awesome, I was missing the event_calendar.js include. Now multiple rows work great.

    I’ll check my other CSSs, at least I know the problem’s on my end (although that’s weird as IE 7 shows OK).

    This is some neat piece of code – again thanks a lot, both for sharing the plugin AND the support you’ve been offering!

    Much appreciated!

  58. I tried “script/generate event_calendar” and received:

    D:/workspace/temp/script/../config/boot.rb:20:Warning: Gem::SourceIndex#search support for String patterns is deprecated, use #find_name
    c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.4.4/lib/active_support/dependencies.rb:376:in `new_constants_in’: You have a nil object when you didn’t expect it! (NoMethodError)
    You might have expected an instance of Array.
    The error occurred while evaluating nil.empty? from c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.4.4/lib/active_support/dependencies.rb:202:in `load_file’

  59. @Lee

    The plugin needs a 2.x version of Rails. From the error message, it looks like you’re running an older version.

  60. [...] Some events don’t start and stop at specific times, but instead last all day. [...]

  61. Hey.
    I am excited to use the plugin, but I am having an issue I can’t seems to resolve. I am getting the error

    undefined method `strftime’ for nil:NilClass

    /Users/eric/.gem/ruby/1.8/gems/activesupport-2.3.5/lib/active_support/whiny_nil.rb:52:in `method_missing’
    /Users/eric/Sites/rails/divott/app/helpers/calendar_helper.rb:12:in `event_calendar_opts’
    /Users/eric/Sites/rails/divott/app/helpers/calendar_helper.rb:19:in `event_calendar’
    /Users/eric/Sites/rails/divott/app/views/home/index.html.erb:12:in `_run_erb_app47views47home47index46html46erb’

  62. Need help regarding this matter. Unable to figure out how to create new event and how to show created events on index page ??
    Thanks in advance

  63. @Eric

    Looks like your @shown_month variable is nil. Is it being set in the controller? It should be a date object.

    @mubashir

    The plugin leaves creating events up to you. It focuses on displaying them within a calendar. At the minimum you could use a basic Rails scaffold for creating/updating/deleting events. As for showing those events, the README does a better job at explaining then I can do here.

  64. Good work on an excellent plugin and calendar!!! I would like to implement a calendar in my rails app to show a kind of time line for 4 or 5 of my models.

    As such I don’t want an “events” model, I just want to be able to build my own events collection from other models and display those items on the calendar.

    for example, I have “tasks”, “Phone calls”, “meetings” etc that I want to display.

  65. Hi Jeff,

    Nice plugin :)

    It’s working perfect but I would need multilanguage month names. I’ve I18n.yml translation files but they don’t work.

    I would like that the events names don’t hide if they are too long. Is it posible to make multiline event names.

    Thank u!

    david.

  66. @Ryan

    I think the plugin can be used towards your purposes. If you create a class that has_event_calendar, then you can call YourClass.create_event_strips(start_date, end_date, event_collection), where you’re creating the event collection from different models. The objects in that collection should just need a couple attributes like name, start_at, and end_at. Let me know how it goes!

    @David

    il8n support is on the feature list http://github.com/elevation/event_calendar/issues#issue/3. I think it would be great to have as well. Maybe I’ll work on this next.

    It isn’t currently possible to have multi-line event names. This is due to how calendar row heights are calculated. I’ll add it to the feature list, but I don’t think there is an easy/quick solution.

  67. Ok Jeff,

    Thanks, I will try to resolve it anyway and if I get it I will tell you. ( I would need I18n to comment your blog! hhehe) ;)

    david.

  68. First I want to take a moment to thank the Elevation folks for putting the time and effort into this plugin.

    I also wanted to announce the release of a plugin that has built off of their hard work to support a different underlying model structure that gives you a little more flexibility with respect to start and end dates. For more details please check out:

    http://highaltitudehacking.wordpress.com/2010/01/11/reservation_calendar_rails_plugin/

  69. Hi, a very nice plugin. I managed to get I18n working for it, just try this:

    In your helper, modify the month_link function:

    def month_link(month_date)
    link_to(I18n.localize(month_date, :format => ‘%B’), {:month => month_date.month, :year => month_date.year}, :class => ‘month_link’)
    end

    and the :month_name_text from the options list:

    :month_name_text => I18n.localize(@shown_month, :format => ‘%B %Y’),

    You also need to hack the core calendar_helper.rb file in order to use the day names from your language file:

    day_names = I18n.t(’date.day_names’)

    Hope this helps

  70. @Mike

    Glad you like the plugin. For one of our projects I used it as is to do something similar to your reservation plugin, where we had two models: Event and EventDate. An event has many event dates. The EventDate model declared has_event_calendar, thus showing each date on the calendar. It worked pretty well. It looks like your plugin formalizes this method?

  71. @RoR developer

    Thanks for the starting point on adding localization. I’ve just updated the plugin.

  72. Thx RoR developer! Nice solution.

  73. Does anyone have any experience using this with conditions for the events. I set up my events to be able to be either public or private, and there are multiple users. My goal is for a logged in user to be able to see their public and private events, then be able to see other users calendars with only that users public events. Anybody have any experience with anything like that or know where I should start?

    Love the plugin by the way!!!

  74. hi
    thank you for your great plugin
    i wonder if it is possible to have a different look, for example the whole year, the week, a simple day and so on …
    is there a possibility ?
    thanx again!

  75. Jeff, awesome plugin! Took me about 5 minutes to get it up in running. I have a quick question though, and maybe someone else can answer it. Right now all events are shown which is fine for starters, but I need to be able to easily supply the calendar with a custom collection of events(like only events in TX, etc.). Where would be the best place in the code to implement this? Can it be done for the controller, or would I need to modify the plugin?

    Thanks!

  76. Meh. I hacked it so it will pass a string of extra conditions down to the query in events_for_date_range.

  77. Well done, Jeff.
    That’s exactly what I was looking for.

  78. I’ve created a Google Group to help ask and answer questions. http://groups.google.com/group/event-calendar-plugin

    I just re-posted these…

    @Charley -> http://groups.google.com/group/event-calendar-plugin/t/971e94fcc409abfa

    @jeff -> http://groups.google.com/group/event-calendar-plugin/t/12c9a8a8babc6ef4

    It would be helpful if people could post these types of questions there from now on. And don’t forget the GitHub Issues page and Wiki as well.

    Thanks!

  79. Thanks for this great plugin! I’m currently working on a rails application for (flexi-)work time scheduling and this calendar exactly fits my needs!

Leave a Reply