Badger Academy - Week 7

It's week 7 at Badger Academy, and it feels like things are really starting to come together. As the codebase begins to take shape, and more of the blanks are being filled in, I'm finding it easier to contribute as there are now more examples for me to refer to and less code to write completely from scratch. I spent a couple of days building the Roles section (Projects > Phases > Roles), on the frontend and feel like I'm really starting to grasp how things are linked together, where code is being called from, and what properties are getting passed from one section to another.

Money, money, money

Tiago and I started the week pair-programming to get the money values working properly. We implemented the money-rails gem, and created migrations to change the money columns to add the suffix '_pence' to them. E.g. the fixed_price column in Phases, was renamed to fixed_price_pence. However, using the monetize method, the suffix is ignored everywhere else, so you can still just refer to the attribute as fixed_price.

We were able to access the monetize method in the models, which creates a money object from the attribute. Money is converted from pounds to pence, and saved in the database as pence. Then we make sure to convert back from pence to pounds in the views, for users. This means that calculations are done using integers, and no weird rounding errors will occur with floats. Also, should we ever go international with Badger Time, or start getting paid in exotic currencies, having everything set up with money-rails should make currency conversions a doddle.

Promises, Promises

Clicking around in the browser, I discovered a bug where the page was rendering before data had finished loading. A phase belongs to a project, and I found that trying to access some of the phases resulted in an error. It turned out that after fetching each project, and then each of the phases for the first project, the data was being registered as fetched before the other phases had been retrieved.

Viktor decided that the best way to solve this issue was through the use of promises, an entirely new concept to me. The basic idea is that they can store tasks in memory, and 'promise' to do something in future, once other criteria have been fulfilled. So you can hold off an action until other tasks have been completed.

The really clever thing about promises is that you can chain them together, so that once a stage in the code is reached, you can start another promise, and then another one, and so on. Then each promise will wait for the required actions to be completed before launching its own action, until you get back to the first promise. Everything will run in the sequence you've set, and you know that the final task won't be run until everything else has finished. Another really useful feature is the .all function, which allows you to run several tasks in parallel, and wait for them all to finish before running another task. This would be much more difficult just using classic node callbacks.

By passing in a silent option, we could hold off on notifying the listeners that data had been fetched, until it truly had all been fetched. It also cut down on the number of times the page was being re-rendered, as previously it was rendering after every single item was fetched, which would get ridiculous once Badger Time was filled with content, (and was already slightly ridiculous with the small amount of example content that's in there currently!).

We installed the Bluebird promise library, and then required it in each file we added promises to.

Here's the code that was added to the Projects store file:

Here's the code from the Phases store, that gets called from the Projects store: