In part 1 we added a placeholder page for our new budget feature and updated our navigation. This time out we are going to look at adding some actual content to the budget page.
Today’s objective
Today we’ll be looking to replace our placeholder budget page with some actual content. We’ll create the basic content we want to display and update our code so the user can set their budget.
Getting started
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 1, or you can grab the code from GitHub.
Clone the Repo:
Terminal
After grabbing the code we should set our local Ruby version and run bundle install
.
Terminal
Terminal
Next let’s create a new branch for today’s work.
Terminal
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.
Terminal
Not too impressive! The first thing I notice is we are missing the current income versus expenses
widget that shows up on the other pages, i.e.
So let’s work on that first.
Adding content to the budget page
First off, let’s get that widget displayed, this is an easy change.
Adding the widget
/app/views/budget/index.html.erb
A pretty simple change, we’ve added a few divs
and included the widget via <%= render 'shared/mtd_ytd' %>
.
We now see the widget showing up.
Next let’s figure out how to display each of our categories along with the current amount spent on that category for the current month. For now we won’t worry about the budgeted
field or any functionality related to the budgeted
field.
Displaying our categories on the Budget page
I’ve manually added in some test data in order to have a few categories and transactions in the database. One thing to note is we should already have a backend query that we can adapt for use on our Budget
page. If we view the reports page, we’ll see our expense report is displaying the exact data we are after.
Looking at how the data is being loaded on the reports page, we’re using a method called expenses_by_category_and_date_range
. So we just need to call into that method from the BudgetController
. The method takes in a date range of the format dd mmm YYYY:TO:dd mmm YYYY
.
Loading the data
So let’s update the controller code.
/app/controllers/budget_controller.rb
Pretty simple, we build up our range
parameter to pass into expenses_by_category_and_date_range
. Then we use the sum
value returned by the method to populate a new spent
attribute on the category
model. In this way we end up with a list of categories along with how much has been spent on those categories for the current month.
The new spent
attribute isn’t something we’ll be adding to the database so we can just use an attr_accessor
. Let’s update the model:
/app/models/category.rb
One other thing to make note of is we’re populating the spent
attribute by comparing the values of the category.id
field. The expenses_by_category_and_date_range
method does not currently return the category id, so we need to update the method to do so.
/app/models/user.rb …line 87
Simple, we just added the id
in the select
and group
statements.
Now it’s time to update the UI!
Displaying the data
Let’s update the view.
/app/views/budget/index.html.erb
So a bit of a code dump, but all we’ve really got here is some HTML with a bit of logic mixed in. We’ve got an if
statement to check if we have any categories to display. If not we output a message indicating the user needs to create some categories. If we do have category records to display we display them in a table. We’re rendering the individual category items in a seperate file via <%= render 'budget_item', item: item %>
so we’ll need to create that.
Terminal
/app/views/budget/_budget_item.html.erb
And with that we now have a pretty decent initial outline of what our page will display.
Adding the budget field
Before stopping for today, let’s add the new budgeted
field. We have a few options for this. We could create a new database table containing a category_id
, user_id
and a budgeted
value. However I think it is reasonable to simply add a new field to the existing categories
table. This avoids the complexity (albeit minor) of adding a new database table / model and logically it is reasonable to think that for each category record a field exists that indicates the amount a user has budgeted for that category.
So let’s create a migration for the new field.
Terminal
We’ll update the migration as follows:
/db/migrate/datestamp
_add_budgeted_to_categories.rb
And now we can run the migration.
Terminal
We need to make a small change to the Category
model so that we can access the budgeted
field.
/app/models/category.rb
Now we just need to update _budget_item.html.erb
… since we want the user to be able to set the value of the budgeted
field we’ll use the functionality of the best_in_place gem to allow for this.
/app/views/budget/_budget_item.html.erb
So we’ve added the field and made it editable via the best_in_place
gem. Since we already have an update
method on the Category
controller we don’t need to make any backend changes. When an edit occurs it will be sent to the update
method of categories_controller.rb
, i.e.
With the _budget_item.html.erb
changes in place we now have an editable budgeted
field.
Sweet!
What about tests?
Actually before wrapping up for the day, let’s take care of one more thing. As we’ve been building out this new functionality we’ve been neglecting our tests… let’s remedy that!
Since we’ve updated our database, the first step is to update our test database.
Terminal
Model tests
Now let’s update the tests for our category model. We’ll add respond_to
tests for the two new fields we added.
/spec/models/category_spec.rb
Straightforward, looking at the rest of the category_spec
, I think it would also make sense to add a validation for the new budget field. We’ll add this at the end of the spec.
/spec/models/category_spec.rb
We also need to add the actual validation.
/app/models/category.rb
And with that, let’s ensure the category
model tests pass:
Terminal
Great!
Budget page tests
Now we should create some tests for the actual budget page. We’ll need a new file for this.
Terminal
As far as the content of the test goes… I am going to vomit out some code and won’t provide much of an explanation… I feel the code is pretty self explanatory however. So our test looks like:
/spec/requests/budget_spec.rb
Let’s ensure the budget tests all pass.
Terminal
And then just for good measure, let’s run the entire suite.
Terminal
Sweet all looks good!
That’s it for today, we can merge our changes and we can remove our current working branch.
Terminal
Summary
We are pretty close to finishing up the implentation of our new feature. Next time out we just need to add in a bit of javascript to calculate the sums and recalculate in the case of an edit. Next time, we’ll be looking to add some actual content to the Budget page.
Thanks for reading and I hope you enjoyed the post!