fiedl/wingolfsplattform — pull request #56 by fiedl (2014-09-18 22:26:26+00:00)
Title: New mode caching mechanism.

With this pull request, we introduce a **new mechanism and new conventions for model caching**.

## Old mechanism

Before this pull requests, we were doing model caching manually:

```ruby
class Foo
def expensive_method
# expensive calculation, which could take several seconds of queries and processing.
end
def cached_expensive_method
Rails.cache.fetch([self, 'expensive_method'], expires_in: 1.week) { expensive_method }
end
def delete_cached_expensive_method
Rails.cache.delete [self, 'expensive_method']
end

def fill_cache
cached_expensive_method
# ...
end
def delete_cache
delete_cached_expensive_method
# ...
end
end

# From outside:
foo.expensive_method # uncached version
foo.cached_expensive_method # cached version
```

## New ways to do the same

There are two new ways to do the same: In variant 1, the instance method takes the responsibility to cache. In variant 2, the caller of the instance method, which in most cases would be a helper or a view, is responsible for requesting the cached version.

Both variants have their use cases, but variant 1 is recommended.

### Variant 1: The expensive method introduces caching by default (recommended)

```ruby
class Foo
def expensive_method
cached do
# expensive calculation, which could take several seconds of queries and processing.
end
end

def fill_cache
expensive_method
# ...
end
end

# From outside:
foo.expensive_method # cached version
foo.cached(:expensive_method) # cached version
foo.uncached(:expensive_method) # uncached version
Rails.cache.uncached { foo.expensive_method } # uncached version
```

### Variant 2: The expensive method is not responsible for caching

```ruby
class Foo
def expensive_method
# expensive calculation, which could take several seconds of queries and processing.
end

def fill_cache
cached(:expensive_method)
# ...
end
end

# From outside:
foo.expensive_method # uncached version
foo.cached(:expensive_method) # cached version
foo.uncached(:expensive_method) # uncached version
Rails.cache.uncached { foo.expensive_method } # uncached version
```

### Under the hood

* [ActiveRecordCacheExtension](https://github.com/fiedl/wingolfsplattform/blob/e40158693d3b247d36730169667c5f2be044d093/vendor/engines/your_platform/app/models/active_record_cache_extension.rb)
* [CacheStoreExtension](https://github.com/fiedl/wingolfsplattform/blob/e40158693d3b247d36730169667c5f2be044d093/vendor/engines/your_platform/app/models/cache_store_extension.rb)

### Watch out!

* The cache invalidation takes at least one second, since the `updated_at` column is part of the cache key. In
specs, use the `wait_for_cache` method if you run into problems. Wiki: https://github.com/fiedl/wingolfsplattform/wiki/Caching

* If you introduce new caching (in both, variant 1 or 2), make sure to call the proper method in the `fill_cache` method of the concerning class. Otherwise, the cache won't be filled in the nightly rake task.

### Advantages

* Less code duplication when writing model caches.
* Ways to make sure to get the cached or the uncached version.

### Wiki

https://github.com/fiedl/wingolfsplattform/wiki/Caching