Skip to content
PLAY VIDEO PLAY VIDEO PLAY VIDEO
By Sean Geoghegan

A Caching Strategy for Large Dynamic Option Lists

One of our clients recently had some performance problems with a page that displayed a very large form. This form had a tonne of select boxes with large lists of dynamically generated options. The options were based on some property of the user, e.g. their home state, and in most cases the list of options were completely different for each state. In total, the select boxes took about 500ms to render!

Typically, caching forms is a bad idea, because the content is specific to a single user. To do it in a way that doesn't mess it up for all users, you would have to cache it on a per-user basis, i.e. something like this:

 <%= cache("big_slow_select_for_#{current_user.id}") do %>
   <%= render_big_slow_select(form, current_user) %> 
 <% end %>

This is less than useful for a couple of reasons. Firstly, it's going to cache it separately for each user, so your hit ratio is going to be pretty low. Secondly, whenever the user changes that value the cache will have to be expired, which is going to make your hit ratio even worse.

Another option is to cache the html based on the selected value, like so:

 <%= cache("big_slow_select_for_#{current_user.value_for_big_slow_select}") do %>
   <%= render_big_slow_select(form, current_user) %> 
 <% end %>

This is better because at least users with the same selected value for the option will share the cache entries. For small lists of options this would probably work reasonably well, but if the option list is large you need to look at the probability of a cache hit. In our example, if there are 7 home states (we are Australian after all) and each home state will generate a different list of about 100 options and the selected values are evenly distributed across those options then the likelihood of a cache hit is something like 1:700, not that good.

But there is a better way. The slow part here, well in our case at least, was the generation of the options list. It was slow because a) it was large and b) it required querying and joining across a bunch of tables to build the list based on other options the user had set. So what we can do is cache that list of options based on the home state value of the user. So, for example, say the options list is based on the user's state, we can have a helper method that builds and caches this options list, like so:

    def build_big_slow_options_list(state)
      Rails.cache.fetch("big_slow_options_list_for_#{state}") do        
        do_something_really_slow_that_builds_an_options_list_for(state)
      end
    end

This will give use cache entries for each variation of the options list. Using the example of home state again, this gives us a cache entry for each home state, which translates to a 1 in 7 chance of getting a cache hit, much better than the 1 in 700 we were getting before.

Now we just use the helper method in a standard Rails form building template:

 <%= form.select(:big_slow_value, build_big_slow_options_list(current_user.state)) %>

And the slow part, building the options list, will get cached. We get a cache hit for every user with the same state, which is going to be a pretty high hit ratio, and we never have to worry about stale caches of old user data since the user's selection is not part of the cached value.

We used this mechanism on the client's app and it reduced the load times for these forms by about 500ms. Win!

Latest Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Webinars

    Webinars

    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

  • Installfest

    Installfest

    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

Get the “reinteractive Review” Monthly Email