The Perils of Cached Data

Mike Diaz
4 min readJan 23, 2020

--

Week 3 at Flatiron School: Software Engineering students pair up to practice our Ruby skills by building CLI apps. The apps exhibit many-to-many relationships and our ability to execute CRUD commands via ActiveRecord. I worked with Tom Humphrey on a simple model where travelers could write journals about their trips. The Journal Entries would be assigned to both a User and a Location, tying our classes together in a neat many-to-many relationship. As we were building, we came across some unusual behavior when attempting to call the D in CRUD: destroy.

entry.destroy

When we executed the function that would delete one of these journals, we would find that it was still appearing in our list.

We double checked that .destroy was doing what we wanted it to — indeed it was removing the row from our database. But the database wasn’t being accurately reflected in our program. So what the heck is going on here??

It turns out this was an issue with cached data. To understand what that means and why it’s relevant, let’s go back to the beginning of our method:

We see a couple of global variables here, identified by a `$` in front of them. These are assigned as global variables because they are defined outside of our methods but need to be referenced throughout our project. $prompt is set to TTY::Prompt.new. TTY::Prompt is a great Ruby gem created by Piotr Murach that provides a ton of menu selection functionality — you can read all about it here. Simply put, $prompt creates a new menu for us.

The global variable that was giving us headaches was $current_user. Our idea here was to prompt a user to log in or create an account and then give them access permissions based on their credentials. For example: I don’t want a user to be able to delete any travel journal that has ever been written, but they should be able to delete their own.

When a user logs in, we set $current_user to the user class instance object user has input. Everything associated with that instance in the moment (this will become relevant later), specifically journal entries, is now attached to the variable. So when we call $current_user.journal_entries.each, we display only the logged-in user’s journal entries as options for deletion. Great! They won’t be able to wreak havoc on others’ hard work.

Now that we’re caught up, we can return the concept of caching. When this method ends, a user can return to the main menu. If they call the code again, they’ll see the same list, including the journal entry they’ve just deleted. When we call $current_user.journal_entries the second time, our program doesn’t take the time to check the database for an updated list of journal_entries. It is using the cached version of $current_user and thus returning stale data (data that has already been collected and stored in a cache, the $current_user variable).

So how do we fix this?

We want to explicitly tell our program to re-query our database, so what better way than to write a line of code?

$current_user = User.find($current_user.id)

This extra line, inserted right after our .destroy method, re-assigns the global variable $current_user. By calling .find on the User class, we force the program to query the database, retrieve an updated object and refresh the global variable. Voila! Here’s our functional code:

Can this be refactored?

Thanks to a tip from our instructor Steven Balasta (by way of our classmate Jerry Huang), we were informed of a great strategy — replacing the use of our global variable with a method!

If, upon login, we assign $current_user to the user_id of the created User instance, we can re-call a fresh version of our instance each time we invoke the global variable by defining it within this method. Rather than having to ask ourselves when it’s best to call a refresh the global variable, we’ll refresh each and every time we reference our user’s attributes. So the final version of our code would have been:

It’s a small change, but I think it makes a difference in saving us margin for error — a precious luxury when it comes to coding.

--

--

Mike Diaz
Mike Diaz

No responses yet