Multi-event .ICS file generation?
Any suggestions for generating an .ICS calendar file containing multiple events from my models? Any experience with Gems(iCalendar vs Ri_cal), or anyone know of good blogposts, etc. detailing the process?
Thanks
I haven't, but it definitely looks like ri_cal hasn't been touched in several years. I'd probably have to recommend iCalendar just based on that but their documentation and API don't appear to be the cleanest.
Wish I had more information for you on it, but I haven't had to create .ics files before. Maybe that'll make for a good screencast.
Thanks Chris.
Yeah, I'm not thrilled with either option. Im going to dig around, might be easier to design a custom solution... or not, we'll see.
"Maybe that'll make for a good screencast."
Haha, It sure would, right about now!
OK after digging around some I decided to dive head into iCalendar. It wasn't to bad just had poor documentation so I had to read the gems codebase to get a feel for what was happening under the hood. Here is my solution for generating multi-event ics files using iCalendar.
I defined a custom method in my Events Controller:
def ics_export
@myevents = Event.all
respond_to do |format|
format.html
format.ics do
cal = Icalendar::Calendar.new
@myevents.each do |myevent|
event = Icalendar::Event.new
event.dtstart = myevent.event_date
event.summary = myevent.name
cal.add_event(event)
cal.publish
end
render :text => cal.to_ical
end
end
end
Awesome! That's not too bad.
I believe you could extract this out into its own class to clean up your controller a bit:
def ics_export
@myevents = Event.all
respond_to do |format|
format.html
format.ics { render text: Ical.new(@myevents).to_ical }
end
end
# app/models/ical.rb
class Ical < Icalendar::Calendar
def initialize(events)
events.each do |myevent|
event = Icalendar::Event.new
event.dtstart = myevent.event_date
event.summary = myevent.name
add_event(event)
end
publish
end
end
Note that in this file you don't need to call cal.
on add_event
and publish
since you've inherited those methods and you're inside the object. I also pulled out publish
to the end so it only gets called once. I think that doesn't need to be run each loop but maybe it does.
This is a much nicer implementation! However, I am running into an error and can't figure out what is happing here...
undefined method `keys' for nil:NilClass
I am not using any method with "keys" in it. But I did notice iCalendar is so perhaps it has Something to do with the inheritance?
Thanks
icalendar (2.2.2) lib/icalendar/component.rb:35:in `ical_properties'
icalendar (2.2.2) lib/icalendar/component.rb:26:in `to_ical'
app/controllers/events_controller.rb:74:in `block (2 levels) in ics_export'
actionpack (4.1.1) lib/action_controller/metal/mime_responds.rb:258:in `call'
actionpack (4.1.1) lib/action_controller/metal/mime_responds.rb:258:in `respond_to'
app/controllers/events_controller.rb:72:in `ics_export'
actionpack (4.1.1) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.1.1) lib/abstract_controller/base.rb:189:in `process_action'
actionpack (4.1.1) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.1.1) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (4.1.1) lib/active_support/callbacks.rb:113:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:113:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
activesupport (4.1.1) lib/active_support/callbacks.rb:229:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:229:in `block in halting'
activesupport (4.1.1) lib/active_support/callbacks.rb:229:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:229:in `block in halting'
activesupport (4.1.1) lib/active_support/callbacks.rb:166:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:166:in `block in halting'
activesupport (4.1.1) lib/active_support/callbacks.rb:166:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:166:in `block in halting'
activesupport (4.1.1) lib/active_support/callbacks.rb:166:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:166:in `block in halting'
activesupport (4.1.1) lib/active_support/callbacks.rb:86:in `call'
activesupport (4.1.1) lib/active_support/callbacks.rb:86:in `run_callbacks'
actionpack (4.1.1) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (4.1.1) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.1.1) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
activesupport (4.1.1) lib/active_support/notifications.rb:159:in `block in instrument'
activesupport (4.1.1) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.1.1) lib/active_support/notifications.rb:159:in `instrument'
actionpack (4.1.1) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.1.1) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
activerecord (4.1.1) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.1.1) lib/abstract_controller/base.rb:136:in `process'
actionview (4.1.1) lib/action_view/rendering.rb:30:in `process'
actionpack (4.1.1) lib/action_controller/metal.rb:195:in `dispatch'
actionpack (4.1.1) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.1.1) lib/action_controller/metal.rb:231:in `block in action'
actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:80:in `call'
actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:80:in `dispatch'
actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:48:in `call'
actionpack (4.1.1) lib/action_dispatch/journey/router.rb:71:in `block in call'
actionpack (4.1.1) lib/action_dispatch/journey/router.rb:59:in `each'
actionpack (4.1.1) lib/action_dispatch/journey/router.rb:59:in `call'
actionpack (4.1.1) lib/action_dispatch/routing/route_set.rb:676:in `call'
rack (1.5.2) lib/rack/etag.rb:23:in `call'
rack (1.5.2) lib/rack/conditionalget.rb:25:in `call'
rack (1.5.2) lib/rack/head.rb:11:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/flash.rb:254:in `call'
rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/cookies.rb:560:in `call'
activerecord (4.1.1) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.1.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:621:in `call'
activerecord (4.1.1) lib/active_record/migration.rb:380:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.1.1) lib/active_support/callbacks.rb:82:in `run_callbacks'
actionpack (4.1.1) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/reloader.rb:73:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.1.1) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.1.1) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.1.1) lib/active_support/tagged_logging.rb:68:in `block in tagged'
activesupport (4.1.1) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (4.1.1) lib/active_support/tagged_logging.rb:68:in `tagged'
railties (4.1.1) lib/rails/rack/logger.rb:20:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
rack (1.5.2) lib/rack/runtime.rb:17:in `call'
activesupport (4.1.1) lib/active_support/cache/strategy/local_cache_middleware.rb:26:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
actionpack (4.1.1) lib/action_dispatch/middleware/static.rb:64:in `call'
rack (1.5.2) lib/rack/sendfile.rb:112:in `call'
railties (4.1.1) lib/rails/engine.rb:514:in `call'
railties (4.1.1) lib/rails/application.rb:144:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
rack (1.5.2) lib/rack/content_length.rb:14:in `call'
rack (1.5.2) lib/rack/handler/webrick.rb:60:in `service'
I wonder if maybe you need to call super()
at the beginning of the initialize method so the Icalendar gets initialized properly.
hmm, just stumbled over this thread.. trying to use this on an invoices calendar, but calender is always empty. I'm on rails 5 and using active admin 2.2 ..
you don't have a web cast about this yet?
well, nevermind, I put it in the controlller on the active admin index page like this:
def index
@myevents = Invoice.ransack(params[:q]).result
super do |format|
format.ics do
cal = Icalendar::Calendar.new
@myevents.each do |myevent|
event = Icalendar::Event.new
event.dtstart = myevent.due
event.summary = myevent.sm_contract.customer.name
cal.add_event(event)
end
cal.publish
render :plain => cal.to_ical
end
end
end
maybe not as smart as your proposal but it's working :-) Still this thread was helpful for me.