A Rails plugin is any directory containing either an init.rb file or
lib dir. Being "plugin-able" does not forbid use outside of Rails.
> 2. Why ActiveRecord? Part of me thinks that a DataMapper kind of
> solution would be better. We could build the models, then write the
> mappings.
Why either? Heavyweight model-first libraries do forbid use outside of
your ORM of choice. Instead, craft a set of mixins to provide
calendaring behavior based on a loose duck-typed API (such as what
Active Model aims to provide).
> 3. RiCal already has validations, but they aren't associated with a
> field in an ActiveRecord::Errors kind of way. What would it look like
> to change that up a bit so that it is?
This is a modeling concern: introduce a validation macro that checks
the recurrence rule and adds an intelligible error message for that
field.
jeremy
>> 2. Why ActiveRecord? Part of me thinks that a DataMapper kind of
>> solution would be better. We could build the models, then write the
>> mappings.
>
> Why either? Heavyweight model-first libraries do forbid use outside of
> your ORM of choice. Instead, craft a set of mixins to provide
> calendaring behavior based on a loose duck-typed API (such as what
> Active Model aims to provide).
>
>> 3. RiCal already has validations, but they aren't associated with a
>> field in an ActiveRecord::Errors kind of way. What would it look like
>> to change that up a bit so that it is?
>
> This is a modeling concern: introduce a validation macro that checks
> the recurrence rule and adds an intelligible error message for that
> field.
Why either? I think the idea was to make it as easy as possible to get
up and running with Rails-friendly (views), correct, persisted models.
Maybe that is a bad goal. Let's define our goal together. Is it to
provide calendaring behavior and macros for use in application
specific classes, persisted or not?
I did not realize that ActiveModel is so extensively module-based.
Having just looked at it briefly, I like where it's going and see why
you would suggest a similar approach.
Is there any possibility of having you, Jeremy, submit a vision for
how this library might look? Perhaps a quick sketch of a few
ActiveRecord classes (Event, RecurrenceRule, whatever) which include
modules from this library and invoke some macros, with relationships
between them and maybe a sample of looking for the Events which show
up on a month view?
Adam Williams
I think that some thought needs to be given to how to model RECURRING
events. And there's really no such thing as a non-recurring event,
only degenerate cases with only one occurrence. I've had one or two
bugs to fix there. <G>
I've been doing some work with webdav, and although for the most part
it's awful, the crucial thing they got right IMHO, is to treat an
event along with all of it's occurrences as a single entity.
I don't see modeling recurrence rules separately in the database.
Most of the rails calendar code I've encountered in the past has
reified each occurrence in the database this has at least two
problems.
First, it can't deal nicely with recurrence rules with no end date
since you can't reify an infinite number of occurrences.
Second, if you want to support recurring events with event times
defined in terms of real time zones, you need to deal with the fact
that an event scheduled to occur every Monday at 7:00 pm in the New
York time zone is going to have different UTC times as the months (and
perhaps the spring ahead/fall back rules) change.
We can't be fooled into thinking that a time zone is just a utc
offset. Base Ruby makes that mistake. Time zones are geopolitical
entities which define how the offset between local time and UTC VARIES
over time.
And by the way, if you don't model events with times in time zones
rather than UTC, you can't naturally model such recurring events.
There has been some discussion on how this is a FAIL on the google
calendar api group of late.
Also, icalendar defines the notion of a floating time which is
interpreted in whatever time zone the user wants. The model needs to
deal with this as well.
Now, I think that the first use case to look at in designing a
persistent model for events is the ability to query for all events
which have occurrences between two times. This is what's needed to
display the calendar, typically you want to show all of the events for
a particular day, week, month etc. This is also required to support
things like the caldav calendar report method.
IMHO I think that the right basic model is to keep all of the complex
timezone/recurrence info in icalendar format, understanding those
complexities is RiCal's claim to fame. I'd just have a text field in
the event model which contains the icalendar data. Treat the event
data as a composed field, and let RiCal do the decomposition.
and design the database so that a time range query works well.
I wrote some initial thoughts about this some time ago
http://talklikeaduck.denhaven2.com/2009/01/26/database-representation-for-recurring-events
There's already API in RiCal to assist implementing time range query.
The OccurrenceEnumerator module which is included by Event and other
components which can have occurrences has a zulu_occurrence_range
method
# Return an array whose first element is a UTC DateTime
representing the start of the first
# occurrence, and whose second element is a UTC DateTime
representing the end of the last
# occurrence.
# If the receiver is not bounded then the second element will be nil.
#
# The purpose of this method is to provide values which may be
used as database attributes so
# that a query can find all occurence enumerating components which
may have occurrences within
# a range of times.
This method deals with the floating time problem by returning the
start time of the first occurrence with the earliest possible UTC time
(i.e. in the time zones just west of the international date line), and
the end time of the last occurrence with the latest possible UTC time
(i.e. just east of the IDL).
So the basic idea would be to have these two values as attributes of
the (Recurring)Event model. To find all events which could have
occurrences within a range, you would convert the range start and end
to UTC (if necessary) and then find all events which overlapped this
range, with a nil last occurrence time being treated as infinity.
After finding all of the Events each one would then be asked for
occurrences within that range. Note that a returned event might not
actually have any occurrence within the range, but as long as those
events are properly handled it should be fine.
Validations
I think it's more than just recurrence rules which need to be
validated. There are other things which can be wrong with an event.
Some discussion on how best to errors in a reasonable form, and how
string validation should be might be in order.
Note that there's an effort called Calsify which is attempting to
tighten up what's considered valid in icalendar data. The name Calsify
came from wanting to simplify icalendar, but like all committees they
can't resist the temptation to 'improve' things. It might be useful
to make RiCal more aware of the Calsify 'best practices' and provide
stricter validation.
On the other hand, I think it's important to follow Postel's
robustness law. I'd recommend using the validation to scrub icalendar
data being produced by an application but not necessarily to reject
icalendar data which has been imported via a feed or caldav.
I guess that's enough of my more than 2 cents on the subject for now.
--
Rick DeNatale
Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
> I think that some thought needs to be given to how to model RECURRING
> events. And there's really no such thing as a non-recurring event,
> only degenerate cases with only one occurrence. I've had one or two
> bugs to fix there. <G>
I understand what you mean here, Rick.
> I've been doing some work with webdav, and although for the most part
> it's awful, the crucial thing they got right IMHO, is to treat an
> event along with all of it's occurrences as a single entity.
I agree with this, too. It's crucial, AFAICT, to being able to query
as you have described elsewhere in your email.
> I don't see modeling recurrence rules separately in the database.
I understand this and agree.
> Most of the rails calendar code I've encountered in the past has
> reified each occurrence in the database this has at least two
> problems.
>
> First, it can't deal nicely with recurrence rules with no end date
> since you can't reify an infinite number of occurrences.
Absolutely.
> Second, if you want to support recurring events with event times
> defined in terms of real time zones, you need to deal with the fact
> that an event scheduled to occur every Monday at 7:00 pm in the New
> York time zone is going to have different UTC times as the months (and
> perhaps the spring ahead/fall back rules) change.
>
> We can't be fooled into thinking that a time zone is just a utc
> offset. Base Ruby makes that mistake. Time zones are geopolitical
> entities which define how the offset between local time and UTC VARIES
> over time.
>
> And by the way, if you don't model events with times in time zones
> rather than UTC, you can't naturally model such recurring events.
> There has been some discussion on how this is a FAIL on the google
> calendar api group of late.
>
> Also, icalendar defines the notion of a floating time which is
> interpreted in whatever time zone the user wants. The model needs to
> deal with this as well.
I have read these paragraphs over and over again. I think I understand
what you mean, but I suspect I don't really. We are presently storing
UTC times, and capturing the time zone of the user who creates the
event, but I have not found that we need to use that time zone. The
event is viewed by people in different time zones, and displayed to
them according to their zone. We don't have anything in the UI to
allow them to say the time is floating.
So, 7:00 PM Eastern Time can be -4 GMT or -5 GMT, depending on DST.
You seem to be eluding to a problem with storing 7:00 PM -4, recurring
monthly. If the start time is January 1, 7:00 PM Eastern Time (Jan 1
2009 19:00:00 -0500 2009), and I ask ri_cal to give me an occurrence
on August 1, won't it be August 1, 7:00 PM Eastern Time (Aug 1 2009
19:00:00 -0400 2009)?
Forgive me if I'm totally missing the point.
> Now, I think that the first use case to look at in designing a
> persistent model for events is the ability to query for all events
> which have occurrences between two times. This is what's needed to
> display the calendar, typically you want to show all of the events for
> a particular day, week, month etc. This is also required to support
> things like the caldav calendar report method.
>
> IMHO I think that the right basic model is to keep all of the complex
> timezone/recurrence info in icalendar format, understanding those
> complexities is RiCal's claim to fame. I'd just have a text field in
> the event model which contains the icalendar data. Treat the event
> data as a composed field, and let RiCal do the decomposition.
>
> and design the database so that a time range query works well.
I agree with this %100, and is why I am pursuing participation in
building this. I think ri_cal is wonderful, and will reduce our code
base considerably and bring us to a more correct and flexible solution.
The query/iteration you describe is essentially what I am doing
already, so that make sense to me. I'd like to better understand the
'floating time' problem/solution. Why wouldn't the Event need to have
a flag indicating that the time is floating, and the ones that aren't
have the exact start time? How is it that the 'correct' start time
isn't lost on non-floating start times?
> Validations
>
> I think it's more than just recurrence rules which need to be
> validated. There are other things which can be wrong with an event.
> Some discussion on how best to errors in a reasonable form, and how
> string validation should be might be in order.
>
> Note that there's an effort called Calsify which is attempting to
> tighten up what's considered valid in icalendar data. The name Calsify
> came from wanting to simplify icalendar, but like all committees they
> can't resist the temptation to 'improve' things. It might be useful
> to make RiCal more aware of the Calsify 'best practices' and provide
> stricter validation.
Jeremy Kemper mentioned having validation macros. What do you think
about that, and how would the responsibilities of having errors for
specific attributes (for association with UI fields, like
ActiveRecord::Errors maintains) be appropriately placed in this new
library or ri_cal?
> On the other hand, I think it's important to follow Postel's
> robustness law. I'd recommend using the validation to scrub icalendar
> data being produced by an application but not necessarily to reject
> icalendar data which has been imported via a feed or caldav.
I think this is wise!
> I guess that's enough of my more than 2 cents on the subject for now.
It's like .02 before the Fed got involved: worth a lot!
I'd like to get to coding something up soonish. You mentioned that
you'd expect it best to start with the queries, which would imply some
kind of persistence. Jeremy talked about having the library be
persistence agnostic. I suppose that adds up to building a reference
implementation of the persistence of the 'calendaring behavior' of
this library, perhaps in ActiveRecord? Maybe we could have an ri_cal/
model hack day? I'd buy pizza and beer!
Adam Williams
>>
>> And by the way, if you don't model events with times in time zones
>> rather than UTC, you can't naturally model such recurring events.
>> There has been some discussion on how this is a FAIL on the google
>> calendar api group of late.
>>
>> Also, icalendar defines the notion of a floating time which is
>> interpreted in whatever time zone the user wants. The model needs to
>> deal with this as well.
>
> I have read these paragraphs over and over again. I think I understand
> what you mean, but I suspect I don't really. We are presently storing
> UTC times, and capturing the time zone of the user who creates the
> event, but I have not found that we need to use that time zone. The
> event is viewed by people in different time zones, and displayed to
> them according to their zone. We don't have anything in the UI to
> allow them to say the time is floating.
>
> So, 7:00 PM Eastern Time can be -4 GMT or -5 GMT, depending on DST.
> You seem to be eluding to a problem with storing 7:00 PM -4, recurring
> monthly. If the start time is January 1, 7:00 PM Eastern Time (Jan 1
> 2009 19:00:00 -0500 2009), and I ask ri_cal to give me an occurrence
> on August 1, won't it be August 1, 7:00 PM Eastern Time (Aug 1 2009
> 19:00:00 -0400 2009)?
>
> Forgive me if I'm totally missing the point.
I'm talking about what you need to do to really exchange with other
calendar apps. You do need to deal with getting an event with times
in defined time zones and with floating times.
And yes the answer is to use something which deals with icalendar time
zones rather than trying to reify occurrences in the database, I'd
suggest RiCal for that job. <G>
The zulu_occurrence_range method allows this to be finessed in the database.
Let's say that I've got an event with a single occurrence which starts
on a floating time, say 20100101T000000 and ends one hour later at
200101T010000
Now, if I'm doing the mental arithmetic correctly, the earliest this
event can occur is at UTC time 20091231T120000Z which happens in time
zones just east of the international date line, and the latest it can
end is 20100101T130000Z which happens in time zones just west of the
IDL.
So zulu_occurrence_range will give those two zulu times,which would be
what was stored in the DB. A range query would return that event
(along with any others which could have occurrences within the range),
then you'd ask the RiCal::Event for occurrences within the range for a
particular timezone, and you'd get the right one for that timezone.
At least that's the idea.
>
>> Validations
>>
>> I think it's more than just recurrence rules which need to be
>> validated. There are other things which can be wrong with an event.
>> Some discussion on how best to errors in a reasonable form, and how
>> string validation should be might be in order.
>>
>> Note that there's an effort called Calsify which is attempting to
>> tighten up what's considered valid in icalendar data. The name Calsify
>> came from wanting to simplify icalendar, but like all committees they
>> can't resist the temptation to 'improve' things. It might be useful
>> to make RiCal more aware of the Calsify 'best practices' and provide
>> stricter validation.
>
> Jeremy Kemper mentioned having validation macros. What do you think
> about that, and how would the responsibilities of having errors for
> specific attributes (for association with UI fields, like
> ActiveRecord::Errors maintains) be appropriately placed in this new
> library or ri_cal?
Sounds like something to explore. Note that there's some new stuff in
edge rails allowing validator classes which might be of interest.
>
>> On the other hand, I think it's important to follow Postel's
>> robustness law. I'd recommend using the validation to scrub icalendar
>> data being produced by an application but not necessarily to reject
>> icalendar data which has been imported via a feed or caldav.
>
> I think this is wise!
>
>> I guess that's enough of my more than 2 cents on the subject for now.
>
> It's like .02 before the Fed got involved: worth a lot!
>
>
> I'd like to get to coding something up soonish. You mentioned that
> you'd expect it best to start with the queries, which would imply some
> kind of persistence. Jeremy talked about having the library be
> persistence agnostic. I suppose that adds up to building a reference
> implementation of the persistence of the 'calendaring behavior' of
> this library, perhaps in ActiveRecord? Maybe we could have an ri_cal/
> model hack day? I'd buy pizza and beer!
Sounds like a good idea. Maybe we could get a few of our local
rubyists to participate. I know for example that Larry K, had been
working on icalendar stuff. Maybe Sean (who owes me in exchange for
all those radiant hack nights <G>).
Do you mind if I solicit participants on Raleigh RB?
Adam Williams
As long as you buy the Pizza and beer. <G>
I already copied you on a note I sent to a few locals.
> I might be interested in coming down if you DO do a Raleigh event...
> just to learn. cc me on event emails pls?
Will do. We'll let the whole list know, in case there are any other
interested individuals.
Adam Williams
Okay, as W.C. Fields said, "There comes a time in the affairs of men,
when you need to grab the bull by the tail, and face the situation!"
Well instead, I've grabbed the bull by the horns. Actually the horns
are probably Adam's since again, he's the one who seems to be prodding
me. <G>
Adam's offered to 'sponsor' a hack session to get started. I thought
that this would help get our thoughts together before that, and start
some BDD. I'll coordinate with Adam and other potential participants
on where and when. Where will be somewhere in the Research Triangle
Park NC area.
Since I'd been thinking about the adjunct plugin for some times, I'd
already come up with a name for it, so I've created a github repo for,
"eventually"
http://github.com/rubyredrick/eventually/tree/master
I've already made the initial commits an empty rails app, with an
almost empty plugin called eventually in vendor/plugins.
I've set it up for rspec and cucumber, and I'd like to suggest that we
get started by writing some cucumber features.
There are spec and features directories both in the repository root,
and in vendor/plugins/eventually. I suggest that we work on fleshing
out the features/stories in vendor/plugins/eventually/features
Note that github seems to be unusually slow today, it's taking tens of
minute or more for a commit to show up on the git hub web interface.
> Okay, as W.C. Fields said, "There comes a time in the affairs of men,
> when you need to grab the bull by the tail, and face the situation!"
>
> Well instead, I've grabbed the bull by the horns. Actually the horns
> are probably Adam's since again, he's the one who seems to be prodding
> me. <G>
Necessity is the mother of many inventions!
> Adam's offered to 'sponsor' a hack session to get started. I thought
> that this would help get our thoughts together before that, and start
> some BDD. I'll coordinate with Adam and other potential participants
> on where and when. Where will be somewhere in the Research Triangle
> Park NC area.
>
> Since I'd been thinking about the adjunct plugin for some times, I'd
> already come up with a name for it, so I've created a github repo for,
> "eventually"
>
> http://github.com/rubyredrick/eventually/tree/master
>
> I've already made the initial commits an empty rails app, with an
> almost empty plugin called eventually in vendor/plugins.
>
> I've set it up for rspec and cucumber, and I'd like to suggest that we
> get started by writing some cucumber features.
>
> There are spec and features directories both in the repository root,
> and in vendor/plugins/eventually. I suggest that we work on fleshing
> out the features/stories in vendor/plugins/eventually/features
Most excellent idea.
When you say 'adjunct plugin', you mean that it will be part of the
example app which uses the library we will be building? That is, is
there another project which is the library itself?
Should we create a new mailing list, so we don't bother the ri_cal
group any further with this secondary labor of love?
Adam Williams
Well, right now it just seemed like the way to initially structure the
project. I think the library will go in the plugin and the outer app,
might serve as an example of use. Perhaps someone with more
experience in making modular rails stuff (Sean?) has a better idea.
We can certainly refactor the structure.
>
> Should we create a new mailing list, so we don't bother the ri_cal
> group any further with this secondary labor of love?
I'd prefer to keep it here, I certainly see the projects as related,
since I can't see spending effort on making it work with older
icalendar gems.
If it reaches a critical mass then we might consider splitting into
two groups, cucumber rode along with the RSpec group for quite some
time before Aslak created a separate group.
> On Tue, Aug 25, 2009 at 10:16 AM, Adam Williams<ad...@thewilliams.ws>
> wrote:
>>
>> When you say 'adjunct plugin', you mean that it will be part of the
>> example app which uses the library we will be building? That is, is
>> there another project which is the library itself?
>
> Well, right now it just seemed like the way to initially structure the
> project. I think the library will go in the plugin and the outer app,
> might serve as an example of use. Perhaps someone with more
> experience in making modular rails stuff (Sean?) has a better idea.
> We can certainly refactor the structure.
Jeremy Kemper's statements were in the back of my mind when I asked
the question. I thought it might be nice to hear how he would expect
to find the structure of things. Refactoring our way into things is
good, to be sure. We'll certainly need to have an example application,
so there is no wasting of time in heading this direction!
>> Should we create a new mailing list, so we don't bother the ri_cal
>> group any further with this secondary labor of love?
>
> I'd prefer to keep it here, I certainly see the projects as related,
> since I can't see spending effort on making it work with older
> icalendar gems.
>
> If it reaches a critical mass then we might consider splitting into
> two groups, cucumber rode along with the RSpec group for quite some
> time before Aslak created a separate group.
Great!
Adam Williams