In part 2 we made some good progress on our new budget feature. Today we’ll finish off the core budget enhancement functionality.
At this point we just need to add some interactive elements to the UI and I also want to add a site wide widget similar to the
current income versus expenses widget. This new widget will provide a visual indicator to the user as to whether they are currently running within their budget.
As previously mentionned I’m not sure this is really a “follow along” type of series, but it is possible to follow along if you wish.
If you’ve been following along you can continue with the code from part 2, or you can grab the code from GitHub.
Clone the Repo:
After grabbing the code we should set our local Ruby version and run
Next let’s create a new branch for today’s work.
With that out of the way, let’s get to it!
Where we’re starting from
Let’s fire up the server and have a quick look at our current budget page.
So our page is looking pretty good. All we need to do at this point is add in our various totals. We’ll also want to make the calculation of the totals dynamic so that when a user updates a budget field, the totals are recalculated without needing to refresh the page.
Let’s get at it!
Adding totals to the budget page
We also need to make a few changes to the
_budget_item.html.erb file. We’ll want to add a couple of classes so that we can easily access the
+ / - fields with jQuery. I also want to display the
spent value without the
- sign, so we’ll add an
.abs transform to it.
The only change above is the classes on the last two
td tags and the aforementionned transform of the
spent value to an absolute number.
+ / - column.
Calculating the plus / minus column
+ / - column we just need to subtract the
spent column from the
budgeted column, and do this for all rows. Let’s see what this looks like.
All we’ve done above is call a function we’ve created,
setPlusMinus, on page load. The function itself is pretty simple. For each row we just subtract
budgeted and place the result in the
+ / - column. We’re using the jQuery format currency plugin for converting the values on the UI to numbers (via
asNumber()) so we can perform the necessary arithmetic on them. We then use the
formatCurrency() function to display the result as a currency.
Notice we are also changing the class of the
+ / - field depending on whether the value is positive or negative. Let’s add the styles we are referencing.
First we need to update
The only change above is the addition of the
Now let’s update the
The above will display
debit values in black,
credit values in red. We’re also adding a bit of padding to
a links so that the
Edit links are spaced a little nicer.
With all the above changes in place, a page refresh (you might also need to clear your browser cache) yields:
Now we just need to do something similar with all the values for the
Total row. I won’t go thru an explanation of each function, they are all variations on the general theme of selecting all the appropriate values and adding them together.
A page refresh will show that our page is now looking pretty much complete:
Making the totals dynamic
One problem with the current implementation is that when the user updates a
budgeted value, the totals don’t update to reflect the change.
This can be fixed pretty easily, we just need to bind to the
bindBudgetValueUpdateSuccessEvent, and calling into that function on page load.
With the above change the totals now update on a budget change.
So that takes care of the budget page functionality!
Adding a “budget” widget
One additional change I would like to make is to add a widget similar to the
current income versus expenses widget.
The first step is to add the new widget file:
The contents of the file will be:
Pretty simple! We’ve created a new
monthly_budget_remaining method (which we’ll need to create) and depending on whether we get a positive or negative number from this method we display either
OVER BUDGET or
ON BUDGET for our status.
We also need to make a few styling updates. We’ll be adding some specific styles for the
budget-status class, and then we also want to pull out the
credit styles from the
.mtd-ytd style definitions as we are going to be using these for the budget widget so want them to be scoped globally. The changes to
layout.css.scss are below:
/app/assets/stylesheets/layout.css.scss …line 44
We’ve added some styling for the
budget-status class and pulled the
credit classes out of the
Since these classes are now global we can remove the
credit classes from
Now we need to create our new method in
/app/models/user.rb …line 63
Fairly simple, all we are doing is summing up our expenses for the month and subtracting that value from the sum of the
budgeted fields for our categories.
Note the budget status widget is an overall budget status indicator, i.e. it is possible to be over budget in a particular category but not have the status indicate the user is over-budget if overall they are not over budget.
One final change we need to make in order to see our widget in action is to add it to the following pages:
Adding the widget is straight-forward, we’ll just place it after the current
render 'shared/mtd_ytd' call. For example:
With these changes in place, we have a budget widget!
A few issues
We have a few minor issues with the current implementation of the budget functionality. One is that the budget widget will not update without a page refresh so won’t automatically reflect changes the user makes to their budget values. This is a pretty minor issue and pretty easy to fix but for now we’ll leave it as is.
The other issue is a bit more annoying. We currently show all categories on the budget page. This doesn’t always make sense, for instance when we have a category that is exclusively for income. For example:
So we see the ‘Pay’ category showing up on the budget page which doesn’t really make sense. There are a few ways we could deal with this:
- Leave it as is, and live with it.
- Change categories so that they are either
incomecategories. This would be a pretty big change to the way we currently handle things where individual transactions are tagged as being either income or expenses. It would also mean we couldn’t have categories that have both income and expense transactions in them. For instance, I use a ‘Miscellaneous’ category which contains both expenses and income.
- Add a new field to categories that indicates whether or not it should be included in the budget.
I think the third solution is likely the best approach. Again, for now we’re going to leave things as is… but next time out we’ll implement this third approach.
We have once again been slacking on making sure we have tests in place for our new functionality. So let’s add some more tests before finishing up for the day.
Adding some tests
We’ll add some tests for the new
user.rb method we created and also for the new budget widget. Let’s start with the
Adding tests for the user method
I won’t provide an explanation for the tests below as I think they are pretty self explanatory. We’re just creating some data and then ensuring we get the expected value back from the
/spec/models/user_spec.rb …line 359 to 408
Let’s make sure the
user tests are passing:
Looks good! Note that these are rather long running tests, we might want to look into improving the performance of these tests down the line. For now we’ll leave them as is however.
Adding tests for the widget
We already have some tests for the existing
mtd / ytd widget in the
shared_examples_for_widget.rb file. Since we now have two widgets, let’s start by renaming our existing file to be more specific to the
mtd / ytd widget.
Now we can create a new file for the budget widget.
The tests for the budget widget are very similar to the tests we created for the
user method. We’re just creating some data and then ensuring we get the expected value displaying in the budget widget.
All pretty much self explanatory!
Now we just need to add the shared budget widget tests to the following files:
Doing so is pretty simple. For example:
/spec/requests/budget_spec.rb …line 22
With all that out of the way, let’s run our full test suite to ensure everything is passing.
So that’s if for today, we can merge our code into our budget feature branch.
So we’ve essentially finished our new budget feature. We just have one annoying little issue to fix up (specifying which categories show up on the budget page) which we’ll take care of next time.
Thanks for reading and I hope you enjoyed the post!