Cache rendered Markdown in the database instead of in Redis

Currently we cache rendered Markdown in Redis in lib/banzai/renderer.rb. Redis is configured to expire keys after a certain period of time (2 weeks). This means that 2 weeks after a document has been rendered it has to be re-rendered, regardless of whether it actually changed or not. Another problem is that every time we need to use the cached data we end up executing a network call to get the data from Redis.

Whenever a document is rendered from an object (= a database record) we already have the database record. As such we can work around the expiration of caches and the extra network calls by just caching the rendered Markdown in a column for the source object.

To change this we first need to know which model fields contain Markdown that should be cached. For every field in this list a new column will have to be added with the following details:

  • Name: X_html where X is the name of the column containing the raw Markdown (e.g. title_html)
  • Type: text (no maximum length)
  • Default: NULL (these columns must not be populated using a migration)
  • Allow NULL: yes

Whenever a model field is rendered Banzai::Renderer should check if the cache column (e.g. title_html) is NULL or not. If it is NULL then Banzai::Renderer will render the Markdown and update the column, then return the rendered HTML. If the column is not NULL then Banzai should immediately return the column's value.

The various models containing Markdown should update the cached columns whenever the source columns change (e.g. using a before_save callback). This ensures that the cached column is updated before it's referenced (preventing long loading times).

Steps

  1. Find all models and their fields that contain Markdown that needs to be rendered. Add this list as a comment to this issue.
  2. Find all code that may render custom Markdown (= Markdown not directly originating from a database column). Add all the file paths/line numbers as a comment to this issue.
  3. Create a migration that adds the X_html columns for every model field found in step 1.
  4. Update the code so that instead of sending Strings containing Markdown to Banzai::Renderer instead an object and a field name is passed, Banzai will then take care of the rest. Thus we'd end up with something like Banzai::Renderer.render_object(some_project, :title).
  5. For any code that uses custom Markdown we can still use Redis if needed, this depends on how many instances there are and what the code in question does.