Skip to main content
Building A Calendar Gem:

Open Source Vlog - Refactoring Our Calendar

Episode 68 · June 30, 2015

Refactoring our calendar to find out which pieces need to be interchangeable

Open Source Refactoring


Earn a free month

Day seven! Can't believe it, whole week in, and we're exploring what it means to build a calendar, so we talked yesterday about how do we do these date ranges and how do we generate a table to make a calendar, and one of the cool things that we left out yesterday was this date range thing. This magical line of code that determines how big the calendar should be. It's pretty sweet, actually, it does a lot of stuff. Actually we can use that, because one of ht pieces I've realized I forgot yesterday is those "Previous" and "Next" buttons, and that's one of the pieces that I totally forgot to do, but also, we tested it in the url and it worked, we just need to make the links. Here we can make our links for that, and we can just say "Previous" and we'll figure out what this url should be, and then we also need the link_to "Next" and figure out what that should be.

We're going to want to put in those two links in here so that they calculate based on the current url what the previous month or view should look like and then the next one, and all of that magic. There's a lot of stuff that we need to do, but this is a very interesting one in that if we were to change the start date parameter in the url, what are we actually doing? What if there's other parameters in there, we can't just tell you to do a calendar on a specific url, we need these buttons to manipulate the parameters or at least just the start date if possible and link back and forth, so we have to think about this a little deeper. This is a problem that I solved in the gem before, and we'll take a look at how I solved that before, I have this previous link, so before you could change the name of the parameter, we're just going to look for the default previous link here. Take a look at what we've got, I'm going to paste this into our app, and we'll see what we've got here. I've used the double arrows for both directions rather than just words because it looks prettier. But I made that so you could configure that. We actually pass in rather than a path. Normally you say meetings_path(:start_date: blablabla) and that would give you the correct url with the current page with a different direction or whatever, a different start date, and that's fine, but because we're a generic calendar we're going to put it on any page, we actually need to write generic code here, and that means that we can't pass in a path. There's no routes that we can use, there's nothing to help us there, we really just need to use the current url and pass in the GET parameter into it. The way that you can actually pull that off with rails is to do a hash as that option. I have made a param variable here which is the start date, but because I've made that dynamic and changeable, it was one of those things that it was a variable instead of just a hard coded key. So then, all you have to do is take the date range and substract a day. If we look at this, what are we actually doing, we're saying: This is a calendar for March, if we look at March 1rst and substract one day, what day will that be? That would be the last day of February, and if we do the exact same thing for the next link, it would be the last day of our range plus one day


<%= link_to "Previous", start_date: date_range.first - %> 
<%= link_to "Next", start_date: date_range.last + %> 

That should in theory be a day into the next view. Here it's a little different because we're looking at the last few days of this calendar and then getting a little bit into the next month, so March calendar has a few days into April, so if we take the last day of the range which is April 4th, then our start date, if we add one day, or the start date for the next for April, would actually be April 5th, but because of the code we've written, it can calculate from April 5th to the beginning of the month and do all of this work. If we refresh this page, we now have next and previous links that if you look down here at the bottom, the meeting start date is set to February 28th, and then it goes back to February 28th, which is super cool. If we click on it again, you can see this start date is January 31st, and it's just doing the sustraction every time, so it will take the very beginning of the calendar and go back one more day so it knows to display the right one, so that's it, and that's awesome. Same with the next, you just add one to the last day and you can start navigating these months and that's all you have to do, it's really cool.

One of the tricky parts here is if you have these, how do you generate a title for the calendar, and really you have to take the start day and figure out what you want to display. For me, for the calendar for month calendars we have to take the start date and we want the month, and we want to just display that. This is the seventh month, we can take the translation and we can take thse same code here


We can get July, "Previous" is June, May, April, March, February, super cool. We can also add in <% start_date.year %> because obviously it's kind of important to know which year so that it prints out the year and voila. We have "Next" and "Previous" links ofr our calendar, and that's actually super duper easy, and we're starting to see that this is code that is going to break when we do different lengths of our calendar. If we've got "Previous" and "Next", that is probably generic enough that if you were to shorten this to a single week long, then cool. That probably is fine, but if it's a single week, a week doesn't really have a month name, maybe you do want to display that, maybe you don't. Maybe you want to say it's week seven of the year, week 9, week 10, or maybe you just want it to say: This is a week in May, these four weeks is May. It's kind of up to you, and the titles in the calendar needs to be something customizable. That piece, definitely, we need to make a note here.


This is one of those pieces that I was struggling with because each time we put these into the options passed into the month calendar, that makes for some really nasty view code for the users of simple_calendar, so I don't want you to pass in some weird lambda or block or whatever to handle this, and I'd really like to be able to clean this up. We're needing to find solutions for these problems, but we should first note out what the problems are. Another thing to note here is that this is for a calculation for the month calendar, and if we take this and we duplicate this, we can comment out this piece, and we can say: Let's do a week calendar, so if we were to give it a start date in this case rather than resetting back to the beginning of the month, and jump into the end of the month, we could just go to that date to the beginning of the week and to the end of the week, and if we re render this calendar now we have a week long one, so if we change the calculation between the current day that we're looking at and where we're going, it allows us to generate different lengths of calendars, so this calculation is actually going to hugely important to how we factor this out as well. We need that to be interchangeable to make all these different calculations for our different types of calendars. That will be a piece that we need to override. We need to override the titles, but if we notice, the code here is working reasonably consistent for generating the table, so maybe it's something that we can pull out into a partial, maybe it's not. If you want to do a four day long calendar, how do you do that? Maybe you have to do something like this, and we could do an agenda, and rather than going to the end of the week, we could just say:

<% date_range = (start_date.beginning_of_week..(start_date + 4.days)).to_a %>

This would allow us to do a five day long calendar actually, agendas are normally four days long. You could do something like this, and then the calculation for the next link should be April 7th, and we'll see that in the url at the bottom here, and this is a little better, but we're noticing that there's a little weirdness going on. This is generating a little too long of a calendar. We don't want the beginning of the week in this case, we want that start date so that we can jump between these consecutively. The start date works differently, so the start day will always be the first day, and then when you go to the next view, the start day is here and then it renders this. So there's never overlap in these cases, but we didn't even have to change our table. This date range has allowed us to be super duper flexible and that's really cool. That means that we just need this date range to be customizable, we need the title of the calendar to be customizable and maybe that's it, there's a lot of other options, we could add in here, but maybe we don't need to do them until they're requested, or maybe we can go back into our GitHub repo and see what were the previous requests on functionality and maybe we could find solutions to those questions. Another thing we need to do is accept an array of events that we can sort out into these days when we render the calendar, so that's on the docket for tomorrow in the next few days of the vlog, but today I hope it's clear that we can pull out these things and figure out what are the key pieces that we need to easily make interchangeable and what can we really hard code and keep within the gem, and I think we found some good things today, and I will talk to you tomorrow. Peace

Transcript written by Miguel


Subscribe to the newsletter

Join 31,353+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.