Shopify/identity_cache — pull request #114 by hornairs (2013-12-13 16:43:48+00:00)
Title: Fix a bug where previously nil-cached attribute caches weren't expired on record creation

Attribute caches can cache nil. If we do some find_name_by_id style attribute cache lookup, and it isn't found in the cache, we go to the database, and if the database returns nothing, we store nil in the cache to allow for cache hits next time.

If a record materializes that has the ID we were originally looking for, that cached nil is now invalid and should be deleted. For record creation, we had a bug in the attribute cache expiry logic that should have deleted that key, and before this change we didn't DEL that key. There was also a mistake in the test which tested that the attribute
key gets deleted.

Similarly to secondary indexes, we need to delete both the key for the old value of the attribute, and the new value of the attribute. So this change is made to the expire_attribute_indexes method, and the test is updated to expect the key to be deleted. The expire attribute_indexes method is also optimized to only issue the delete for the same key once.

In Shopify, this manifested as a redirect bug. If you visit a store's `/foo/bar` URL, and no page exists with that URL, we trigger the 404 action. The 404 action does a

```ruby
Redirect.find_target_by_path("/foo/bar")
```

to see if a redirect exists for that path, and if so, gets the target back and can redirect the user there. If that redirect doesn't exist, nil gets cached for that attribute index. If, later, that redirect is created, this bug meant that the attribute index wasn't expired, and so the cached nil would live on. This means that successive calls to `find_target_by_path` wouldn't find the new redirect that now existed, giving the impression the redirect "doesn't work".

@arthurnn @dylanahsmith for review please. If you guys wouldn't mind getting to this sooner rather than later I would appreciate it, apparently some plus customers are angry.