jeudi 21 mai 2015

How to store nil with Rails.cache.fetch & memcache?

I have an existing Model singleton method triggering expensive database queries that I want to model cache. To do this, I wrapped a Rails.cache.fetch call around the method in question:

  # apps/models/specialist.rb
  def city
    Rails.cache.fetch([self.class.name, self.id, "city"], expires_in: 23.hours) do


      # expensive legacy query:
      if responded?
        o = offices.first
        return nil if o.blank?
        return o.city
      elsif hospital_or_clinic_only?
        (hospitals.map{ |h| h.city } + clinics.map{ |c| c.cities }).flatten.reject{ |i| i == nil }.uniq.first
      elsif hospital_or_clinic_referrals_only?
        (offices.map{ |o| o.city } + hospitals.map{ |h| h.city } + clinics.map{ |c| c.cities }).flatten.reject{ |c| c.blank? }.uniq.first
      else
        nil
      end

    end
  end

Executing .city on all records used to take 16 seconds; with this Rails.cache.fetch block it only dropped to 7 seconds because half the records were still triggering database calls.

When I investigated I discovered that when the city method returns nil, Rails.cache does not write the result into memcache -- meaning half my specialist records still trigger expensive database lookups despite being "cached"

How do I force Rails.cache.fetch to store the value of nil when using memcache so that another database lookup to find nil again isn't triggered?

Aucun commentaire:

Enregistrer un commentaire