Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-4680

Add a cache_version implementation to be used with rails 5.2 caching

    • Type: Icon: Improvement Improvement
    • Resolution: Unresolved
    • Priority: Icon: Minor - P4 Minor - P4
    • None
    • Affects Version/s: 7.0.2
    • Component/s: None
    • Environment:
      Rails 5.2.2
      Mongoid 7.0.2

      Rails 5.2 implements a #cache_version method that gets called by ActiveSupport caching. The method simply gets a usec-formatted timestamp String from the updated_at timestamp.

      This method is absent from mongoid. Therefore, when using a simple cache directive in a view:

      <% cache @post do %>
        <%= render @post %>
      <% end %>

      ... the code will fail with a stack level too deep exception. The exception is caused by ActiveSupport::Cache#expanded_version, which is a method deep down the call chain of the "cache" method called in the view above. This method first attempts to call #cache_version on the model, which will fail with mongoid, since it lacks this method. (With ActiveRecord, we would exit out here, returning the timestamp.) Next, it checks if the argument is an Array; it is not, so we move on. Next, it checks if the model responds to #to_a. Our model does respond to #to_a, returning an array with the sole element being the model. The method then calls itself again recursively on that array. On the next iteration, #expanded_version fails again since Array does not implement that method. Next, it checks if the argument is an Array, and now it is, so it calls itself again for each element of the Array. Now, we have an infinitely recursive loop of the model being converted to an Array and placed inside more Arrays, until we get a "Stack level too deep" exception.

      For our project, I've patched the code as follows:

      module Mongoid
        module Document
          def cache_version

      However, this is obviously not a suitable solution for the project as a whole, since only models with Mongoid::Timestamps will be able to access an updated_at timestamp. I'm not sure how you want to solve this, but I do believe that Mongoid should at least return nil for this method if the timestamp is not present in order to retain compatibility with ActiveRecord code inside ActiveSupport's caching code.

            Unassigned Unassigned
            dan@cacheventures.com Daniel Arnold
            0 Vote for this issue
            4 Start watching this issue