Blog


Mar

Working with time zones in Ruby on Rails


Rails provides great tools for working with time zones but there's still a lot of things that can go wrong. This blog post aims to shed some light on these gotchas and provide solutions to the most common problems.

The one that probably has tricked me the most times is the fact that Rails fools you to believe it got you all covered all the time (pardon the pun). Don't get me wrong. I want Rails to do as much work for me as possible. But I've learnt the hard way that I can't get away with not knowing when and how Rails is helping me. Another gotcha is the fact that you have more time zones in play than you might first believe. Consider the following: db, server, dev machine, system configured, user specific configured and the browser.

Configure your Rails app

So what tools do we have at our disposal as Rails developers? The most important one is the config.time_zone configuration in your config/application.rb file. ActiveRecord will help you convert from and to (which the documentation fails to explain) UTC and the time zone of your choice. This means that if all you're doing is having users post times through a form and use Active Record to persist it you're good to go.

Processing time information

So what about actually doing something with the time information before persisting it? That's when it becomes tricky.

Parsing

When parsing time information it's important to never do it without specifying the time zone. The best way to do this is to use Time.zone.parse (which will use the time zone specified in config.time_zone) instead of just Time.parse (which will use the computer's time zone).

Work with Numerical and ActiveRecord attributes

Method calls like 2.hours.ago uses the time zone you've configured, so use these if you can! The same thing is true for time attributes on ActiveRecord models.

post = Post.first
post.published_at #=> Thu, 22 Mar 2012 00:00:00 CDT -05:00

ActiveRecord fetches the UTC time from the database and converts it to the time zone in config.time_zone for you.

Date vs Time

Time has date information but Date does NOT have time information. Even if you don't think you care you might realize that you do sooner then later. Be safe and use Time (or DateTime if you need support for times very far from the present).

But let's say you're stuck with a Date that you need to treat as a Time, at least make sure to convert it to your configured time zone:

1.day.from_now # => Fri, 03 Mar 2012 22:04:47 JST +09:00
Date.today.in_time_zone # => Fri, 02 Mar 2012 00:00:00 JST +09:00

Never use:

Date.today.to_time # => 2012-03-02 00:00:00 +0100

Querying

Since Rails know that your time information is stored as UTC in the database it will convert any time you give it to UTC.

Post.where(["posts.published_at > ?", Time.current])

Just be sure to never construct the query string by hand and always use Time.current as the base and you should be safe.

Working with APIs

Supplying

Building a web API for others to consume? Make sure to always send all time data as UTC (and specify that this is the case).

Time.current.utc.iso8601 #=> "2012-03-16T14:55:33Z"

Read more about why iso8601 is advisable here: http://devblog.avdi.org/2009/10/25/iso8601-dates-in-ruby/

Consuming

When you get the time information from an external API which you don't have control over you simply need to figure out the format and time zone it's sent to you with. Because Time.zone.parse might not work with the format you receive you might need to use:

Time.strptime(time_string, "%Y-%m-%dT%H:%M:%S%z").in_time_zone

This assumes time_string a iso8601 formated string. strptime will throw a very unintuitive error complaining on the format argument when in reality the problem is that the time string's format mismatches the format template argument. in_time_zone defaults to use the Rails configured time zone.

Why there's no strptime method on Time.zone when there's a parse beats me.

Working with multiple user time zones

Many systems needs to support users entering and viewing time information in a variety of time zones. To achieve this you need to store each user's time zone (probably just one of the time zone string names found in rake time:zones:all). Then to actually use that time zone the most common pattern is to simply create a private method in your ActionController and run it as an around filter.

around_filter :user_time_zone, :if => :current_user

def user_time_zone(&block)
  Time.use_zone(current_user.time_zone, &block)
end

This will do the same thing as config.time_zone but on a per request basis. I still recommend to change the default config.time_zone to a time zone that is a good default for your users. (Thank you Matt Bridges for pointing out the potential problems with using a before_filter instead of an around_filter.)

Testing

All the above is something that your tests should catch for you. The problem is that you as the user and your computer as the development server happen to reside in the same time zone. This is rarely the case once you push things to production.

There is Zonebie, a gem that helps you deal with this. I haven't had time to try it out myself yet, but it looks promising. If you find this to be overkill, at least make sure that your tests run with Time.zone set to another time zone than the one your development machine is in!

Cheat Sheet

DOs

2.hours.ago # => Fri, 02 Mar 2012 20:04:47 JST +09:00
1.day.from_now # => Fri, 03 Mar 2012 22:04:47 JST +09:00
Date.today.in_time_zone # => Fri, 02 Mar 2012 22:04:47 JST +09:00
Date.current # => Fri, 02 Mar
Time.zone.parse("2012-03-02 16:05:37") # => Fri, 02 Mar 2012 16:05:37 JST +09:00
Time.zone.now # => Fri, 02 Mar 2012 22:04:47 JST +09:00
Time.current # Same thing but shorter. (Thank you Lukas Sarnacki pointing this out.)
Time.zone.today # If you really can't have a Time or DateTime for some reason
Time.current.utc.iso8601 # When supliyng an API (you can actually skip .zone here, but I find it better to always use it, than miss it when it's needed)
Time.strptime(time_string, "%Y-%m-%dT%H:%M:%S%z").in_time_zone # If you can't use time.zone.parse

DON'Ts

Time.now # => Returns system time and ignores your configured time zone.
Time.parse("2012-03-02 16:05:37") # => Will assume time string given is in the system's time zone.
Time.strptime(time_string, "%Y-%m-%dT%H:%M:%S%z") # Same problem as with Time#parse.
Date.today # This could be yesterday or tomorrow depending on the machine's time zone.
Date.today.to_time # => # Still not the configured time zone.

Epilogue

I hope you've learned something from this post. I sure did while writing it! If you have any feedback on how it can be improved, or if you spot any errors, please let me know by posting a comment below!

Ruby and Rails version

This article was first written in March 2012. Back then Rails 3.2 was the new hot and as you all know a lot happens in Rails-land in two and a half years and will continue to do so. I will do my best to keep the article accurate and up to date with the latest versions of Rails. If you spot anything that is reported deprecated or not working please let me know in the comment section below!

  • Article publish date: 2012-03-20
  • Article last updated: 2015-02-27
  • Last verified Ruby version: 2.2.0 (p0, r49005)
  • Last verified Rails version: 4.2.0

There is a git repository which you can clone:

git clone git@github.com:ramhoj/time-zone-article.git
cd time-zone-article
bundle install
rake db:create:all db:migrate db:test:prepare
rspec spec/

The Rails application is running on the version defined above and has been verified to work under the described Ruby version above. If you want to make sure things are working in the version of Rails or Ruby that you're using please fork the repository and make the necessary adjustments and run the test suite. If you want more in-debt, hands-on of the examples this repository's test suite aims to help with this too.

Changelog

See the git repository's commits.

Mar

Campfire Stories: Feb 27 - Mar 2


We love Campfire at Elabs. Even though we're all in the same office, we use Campfire to share links, images, videos, etc. Some are useful, some are funny, and some are just disturbing. We thought we'd share them with you.

Monday, February 27

Polstjärna

Polstjärna is a Swedish foundation whose vision is to support children and young people in Sweden in the risk zone of social exclusion.

We designed some banners to help them spread the word.

http://polstjarna.se/polstjarna/vanner/

Best friends

Enrique's picture of our office

Elabs' office by @ecomba

Last year we had our friend Enrique working with us for a couple of days. In addition to being a great developer and all-around nice guy, Enrique is also a good photographer. Here's a picture he took of our office during his stay here.

You can read more about Enrique's experience working with us here: http://www.ecomba.org/post/17558226325/elabs.

Tuesday, February 28

Harvest for Mac

Harvest, the tool we use for time tracking, has released a desktop client for Mac OS X, helping us keep our time tracking even more accurate.

http://www.getharvest.com/mac

Minimalist coffee table

Vic Coffee Table

http://minimalissimo.com/2012/02/vic/

Frank Chimero's new site

http://www.frankchimero.com/

ProjectPuzzle competitor

In between our consulting projects, we've been working on an app to help with project scheduling. We call it ProjectPuzzle. Last week, one of our competitors launched their attempt at solving the same problem: http://floatschedule.com/.

They even got a TechCrunch article written about them: http://techcrunch.com/2012/02/28/float-does-simple-scheduling-for-teams-and-simple-is-hard/.

Wednesday, February 29

Throne of JS

One of our favourite conferences ever was FutureRuby, hosted by Unspace in Toronto in 2009. Now Unspace is back with a new conference, and we're very excited: http://throneofjs.com/.

Twitter conversation

Minimalist Pixar Posters

Wall-e

http://www.probablybest.co/2012/02/minimalist-posters-of-pixar-films/

CJ reaches Inbox 0

Inbox 0

Didn't last long unfortunately.

Thursday, March 1

"Font-Embedding Icons: This Is a Big Deal"

http://somerandomdude.com/2010/05/04/font-embedding-icons/

Hand crafted, infinitely scalable & royalty-free icons for user interface designers

http://pictos.cc/

Friday, March 2

"Give it five minutes"

Dismissing an idea is so easy because it doesn’t involve any work. You can scoff at it. You can ignore it. You can puff some smoke at it. That’s easy. The hard thing to do is protect it, think about it, let it marinate, explore it, riff on it, and try it. The right idea could start out life as the wrong idea.

http://37signals.com/svn/posts/3124-give-it-five-minutes

Coffee

Coffee

Lots of excitement about coffee at the office. This week Camilla from Coffee & Memories will be delivering our new coffee making equipment.

Gridset

Create advanced grid systems on the web.

http://www.gridsetapp.com/

"Ruby patterns from GitHub's codebase"

Zach Holman shares some tips and techniques from GitHub's own codebases.

http://zachholman.com/talk/ruby-patterns

Curious that he doesn't talk about how they handle mass-assignment issues.

MailChimp Guides with book covers

MailChimp guides

MailChimp has designed individual book covers for each of their how-to guides. Beautiful work.

http://mailchimp.com/resources/

Feedback

We're considering making this a regular feature on the blog. This is an experiment, so please let us know what you think!

Feb

Capybara and testing APIs


Before you read this blog post, go read the Capybara README. Back? Good. Did you see any mention of methods like get, post or response? No? That's because those don't exist in Capybara. Let's be very clear about this, Capybara does not have those methods. So when you're writing a test like this:

visit '/'
response.body.should have_content("Hello")

Or possibly:

get '/'
page.should have_content("Hello")

Now you know why this couldn't possibly ever work. Because while visit and have_content are indeed part of the Capybara API, get and response are not. If these methods are defined inside your test/spec context, some other framework is defining them, most likely RackTest, and that framework and Capybara do not interact. Capybara knows nothing about what happens when you call get and likewise, RackTest knows nothing about what happens when you call visit.

For most people who have used Capybara for a while, this is old news. They tried variations like the above and they didn't work, they moved on and learned from those mistakes. The interesting question is why these methods do not exist in Capybara. Omitting these methods was a very conscious decision, a decision based on the following premise: Capybara is not a library suited to testing APIs.

There you have it. Do not test APIs with Capybara. It wasn't designed for it.

Capybara simulates user behaviour. Its API was designed to run against as large a variety of backends as possible. To achieve this, we have placed severe restrictions on what you can and cannot do with Capybara. We have limited the API to the most common subset of actions that a user would want to perform in a web application. This immediately precludes exposing the details of HTTP. A user knows exactly how to submit a form, but they have no idea that that form is sent as an HTTP POST request with certain HTTP headers.

I've seen so many people hack into the internals of the RackTest driver in Capybara. I want to make it clear that doing something like the following is using a private API, which is liable to change at any point (yes, even point releases):

page.driver.browser.post('/foo', data: "here")

Don't ever do this! Why would you? You could just use RackTest directly. In fact, as we saw before, it's probably already included in your spec context. So why make it harder than it needs to be:

post '/foo', data: "here"
last_response.body.should contain("Hello World")

Why would you write page.driver.browser.post when you could just write post? See that doesn't make any sense.

By extension, Capybara assumes the response to be HTML, if you're parsing page.body or page.source as JSON or XML, why not just use RackTest instead? You'll have a much nicer, cleaner API which won't break in the future.

tl;dr:

Use RackTest for testing APIs, use Capybara for testing user behaviour.

Jan

Why Serenade.js?


Yesterday I opened up the repo for Serenade.js to the public, and discussion ensued on Twitter and Hacker News. A lot of people are asking why we would need yet another client side framework, so I thought I would write down why I think Serenade offers something we haven't really seen yet.

MVC

A lot of the popular client side frameworks today claim to follow the MVC pattern. But the way the MVC pattern was originally envisioned is very different from what any client side MVC framework is doing today. This paper outlines the MVC pattern used by the Smalltalk-80 interface, developed at Xerox PARC. It's that old, and still very relevant.

The paper outlines the responsibilities of the MVC triad as follows:

Views: Present data from the model and update it if it changes, notify controllers of user interaction events.
Controllers: React to user interaction events by instructing the model to perform certain actions.
Models: Handle business logic and persistence, notify the view of any changes to the data.

A notable difference to how most MVC frameworks today handle this is that it is often the controller's responsibility to present data to the view, and make sure that that data is up to date, giving the controller much bigger responsibility than it would otherwise have. Oftentimes the controller is also responsible for rendering the view, and as in Backbone, for placing it in a particular location on the page.

By clearly defining the role of the controller as only reacting to user events, we can isolate it from a lot of concerns. We are following the single responsibility principle, and as an added bonus, we've made it possible to test our controllers without even involving the DOM.

I tried to follow the Smalltalk-80 style of MVC very closely in Serenade. The almost unexpected side effect of this was that neither models, nor controllers needed any kind of special logic. In Ember.js for example, all objects you want to use inherit from Ember.Object. In Serenade you can use any JavaScript object as a controller or a model, which means you can use it in an existing application or in just a fragment of an application without having to bend your entire app around it.

Templates

The template language in Serenade.js is very carefully constructed so that binding data to both attributes and text is possible, without a lot of additional code in the templates, and without any additional markup. Consider the following example:

h1[title=@name] "His name is " @name

The resulting markup from this would look like this:

<h1 title="Jonas">His name is Jonas</h1>

No additional markup at all! And yet, when I update name to "Peter", the markup just magically changes to this:

<h1 title="Peter">His name is Peter</h1>

And it does this without changing anything that doesn't need to change. The text "His name is" for example is not affected at all by this update.

I came to the conclusion that doing this is only really possible by writing a purpose built template language.

Let's look at this:

ul#comments
  - collection @comments
    li @title

Which would generate something like this:

<ul id="comments">
  <li>Hello</li>
  <li>Awesome</li>
</ul>

Just adding another comment by pushing it onto comments post.comments.push({ title: 'It works' }) would append it at the end:

<ul id="comments">
  <li>Hello</li>
  <li>Awesome</li>
  <li>It works</li>
</ul>

With no additional markup, with nothing explicit needed to make this dynamically update. It's all simple, clean and efficient. Without writing a custom template language this would simply not have been possible.

In contrast, frameworks like Ember and Batman need to add a lot of additional markup for similar functionality, and it's much more difficult for them to do these kinds of things without unexpected side effects.

jQuery

I'm not a huge fan of jQuery. It does what it does very well, and I use it on a majority of projects, but sometimes I want to use something else. I really intensely dislike the fact that pretty much all client side frameworks depend on jQuery. It stifles innovation because it makes it impossible for competitors to have a chance. I wanted to use MooTools for a project recently. It would have been a better fit. But I couldn't, because my framework forced me to use jQuery, and I didn't want to use more than one library.

As far as I can see, Batman is the only framework that is usable without jQuery, using Batman.Solo. Kudos to the Batman.

Serenade has no dependencies. It achieves everything it does by using normal DOM manipulation. This means we probably have to give up on ever supporting IE6, since it has too many weird quirks to work around, but all other browsers in use today, yes even IE7, work without needing a lot of tweaking.

And as an added bonus, if you are using jQuery, just call Serenade.useJQuery() before rendering any views and Serenade will use jQuery for event bindings, instead of its own custom code.

Clear point of entry

In the end we want to use frameworks client side to dynamically manipulate the DOM. I found that most frameworks didn't start at this point though. There are routers, controllers, dispatchers, and all other kinds of things that you would need to add in order to actually get to the point where DOM nodes are created.

Serenade turns this whole concept on its head. We start off by generating DOM nodes. No routers, no dispatch, nothing. Just render a view and insert it into the DOM:

var element = Serenade.view('h1 "Hello world"').render();
document.appendChild(element);

Want to put some data into this?

var model = { name: 'Jonas' }
var element = Serenade.view('h1 "Hello" @name').render(model);
document.appendChild(element);

As you can see you can use Serenade like a template engine. In fact you could use it together with a framework like Backbone, just to render templates. You could specify your Backbone views as the controller in Serenade, and bind events from the view. Cool stuff. Serenade is extremely flexible in how you can use it, and that's because it has a single, simple, point of entry.

Small

Serenade is just 9k gzipped, so it doesn't require a huge download. By comparison, Ember is 37k gzipped. That's more than four times the size! Plus it depends on jQuery, which is another 31k.

But aside from being small in file size, Serenade is also small in concept. It tries to solve one single problem, abstracting away DOM manipulation, and very little else. The model layer abstractions it provides are just helpers to simplify the communication between models and views.

The one other feature Serenade provides is caching, which I've found to be incredibly hard to implement and maintain, and really wanted the framework to take of for me. Transparently and automatically caching stuff in local storage is a huge win, especially for mobile applications.

JavaScript-y

Some of the comments on HackerNews complained about the use of CoffeeScript and especially its classes. I think that's kind of unfair. Serenade is written in CoffeeScript and internally makes a lot of use of CoffeeScript classes. But you're not forced to use them in your application at all.

Let's first clear up that CoffeeScript classes are nothing else than fancy syntax for JavaScript's prototypal inheritance, and the fact that they are called classes, is just calling them what prototypal inheritance is used for in 99% of cases.

As I mentioned before, you can use any JavaScript object with Serenade. The first few examples in the README show how to extend regular JavaScript objects with Serenade.Properties, so that you can get dynamic view bindings without using any constructors. This was very important to me. I didn't want to force people to use constructors if they didn't want to. I didn't want to impose how to create objects at all. Using Serenade.Model is definitely the path of least resistance, but you don't have to use it if you don't want to.

I think that Serenade is a lot more conservative in pushing you towards a class-based way of writing your apps than any framework currently out there. Maybe this doesn't come across very well in the documentation, I'll happily accept suggestions for improvements.

Testability

Unit tests are still unpopular in JavaScript land, but for those that do love them, Serenade makes it incredibly easy to test your application logic. Since templates are logic-less, unit testing them is unnecessary. Instead you can focus on testing controllers and models. Since neither of them interact with the DOM at all, you don't need the DOM to test them, which means you can test them completely in isolation. That's a huge advantage.

Conclusion

Serenade is not radically different from other options out there, I am well aware of that. But the devil is in the details. I hope that people who have had experience writing Backbone or Spine apps or have used other frameworks, will appreciate how simple Serenade is, and yet how it solves a lot of problems which are incredibly annoying and difficult and tedious to solve otherwise. It's not a revolution, it's an evolution.

Dec

The Year 2011 — A Summary


Wow, another year over already. It feels like it was just recently that I wrote a summary of 2010. Tomorrow is Christmas Eve, so it's about time that I try to sum up this year. And what a year it's been.

One of the highlights this year, just like last year, was our conference Nordic Ruby. I feel like this year was even better than last year, with amazing speakers such as Chad Fowler and Aaron Patterson, a party on an 18th century style ship, and 150 fantastic attendees. Next year we're trying something quite different, and I think it's going to be awesome. Keep a look out for the new web site for Nordic Ruby 2012.

Aaron Patterson at Nordic Ruby 2011

Aaron Patterson at Nordic Ruby 2011. Photo by Athega.

Right around the same time as Nordic Ruby, we said goodbye to our partners at Edithouse, and moved to our own space. Our new office is in a fantastic 19th century building, the old offices of the famous Gothenburg camera makers Hasselblad. We love our new office, and others seem to like it too, as we made the finals in a competition for Sweden's nicest office. Feel free to come visit us, we love having guests. If you can't make it, check out the pictures of our new office.

Our new office, in the Hasselblad building

We didn't just move out from Edithouse's office, but we also bought back their shares in Elabs. Right now I'm the full owner of the company. The main reason for this was that the collaboration that we envisioned when I started Elabs together with Edithouse never happened. In 2008 and 2009 Edithouse's business changed, and we set our own course. Our own office and ownership reflects our independence, and that feels great. Personally, I still want to say Thank you to Edithouse for helping get Elabs off the ground in 2008.

Another side of our move was that we decided to close down our Stockholm office. While we had some great projects there, for clients like Bonnier's Mag+ and TV4 Play, it was hard having people spread out. One of the best things about Elabs is our culture. Our way of working together, and our camaraderie. Extending that across the country wasn't easy, and it didn't feel fair to Ingemar and Dennis, working by themselves in Stockholm. We asked them if they wanted to join us in Gothenburg, but they decided to stay in Stockholm, and are now working for our clients Mynewsdesk and Mag+. I wish them the best of luck there.

To make up for the loss of Ingemar and Dennis, we've started hiring again! In August, we welcomed Kim Burgestrand to our team. Kim had been freelancing with us while he was on a break from his studies, and we're very happy that he decided to join us full-time. We'll be hiring more developers next year, so if you're interested in joining a fantastic team, let us know!

In 2011, we really ramped up our public speaking. We spoke at a whole bunch of different conferences all over the world. Here's a list, with links to videos of most of them:

Phew! Quite intense! In between working on client projects and speaking at conferences, our developers still found time to release some great open source projects. Nicklas released his Rails account management engine bento, and Anders released the model factory jay_z and the restful HTTP library resto. Kim did a bunch of work on Hallon, his delicious Ruby bindings to the official Spotify API. Jonas released capybara 1.0, an integration testing library used by most Ruby developers. Later in the year, he also released the brand new library turnip, an alternative to Cucumber.

In recognition for his outstanding open source efforts, Jonas received a Ruby Hero Award at RailsConf in May. We're so proud of him!

Jonas Nicklas, one of the Ruby Heroes 2011

During the year we've had the opportunity to work with some fantastic people. We've worked with some great companies in the US (such as Engine Yard, Stackmob, and LivingSocial), as well as some cool Swedish startups (like Naturkartan and Saltside), and some big established companies like TV4 and Bonnier. A big thank you to all of our clients! We're looking forward to more great projects next year.

Yesterday, our last day of work this year, we said goodbye to Antony. Antony's been working with us for almost two years, and he's been a fantastic part of the team. Now he's striking out on his own with a project related to his other big passion, photography, and we wish him the best of luck. Thank you Antony for all your great work, and for keeping our spirits high at the office. We'll miss you!

Now were taking a break over the holidays, and we'll be back on January 2nd, ready for another exciting year.

Happy holidays!

/ CJ & the Elabs team

Merry Christmas from Elabs

PS. If you want to keep up with what we're doing, follow us on Twitter or check out our Facebook page. Thanks!