Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

make it possible to work with proxy classes like ActiveRecord::Associ…

…ations::AssociationCollection where you really want to control what methods get called on them
  • Loading branch information...
commit b1a256494537ae20af56414dfca5526166b382da 1 parent 65c47cf
@seamusabshere authored
View
6 CHANGELOG
@@ -1,3 +1,9 @@
+0.2.3 / 2012-04-06
+
+* Enhancements
+
+ * Make it possible to work with proxies by defining #to_cache_key which---unlike #as_cache_key---does not cause #class to be run
+
0.2.2 / 2012-03-02
* Enhancements
View
34 README.markdown
@@ -54,19 +54,6 @@ If you're caching methods ActiveRecord objects (aka instances of `ActiveRecord::
end
end
-If you find yourself passing association proxies as arguments to cached methods, this might be helpful:
-
- user = User.first
- Foo.bar(user.groups) # you're passing an association as an argument
-
- class ActiveRecord::Associations::AssociationCollection
- def as_cache_key
- @finder_sql
- end
- end
-
-Otherwise the full object will be marshal dumped **just to get a cache key**.
-
## Debug
CacheMethod can warn you if your obj or args cache keys are suspiciously long.
@@ -92,7 +79,7 @@ or this might even work...
See `Config` for the full list of supported caches.
-== Defining a #as_cache_key method
+## Defining a #as_cache_key method
Since we're not pure functional programmers, sometimes cache hits depend on object state in addition to method arguments. To illustrate:
@@ -110,6 +97,25 @@ get_latest_entries doesn't take any arguments, so it must depend on my_blog.url
If you don't define `#as_cache_key`, then `cache_method` will `Marshal.dump` an instance.
+## Danger: #to_cache_key
+
+Let's say you want need cache keys from classes that undefine the `#class` method (how annoying). You can define `#to_cache_key`, but **make sure it identifies the class too!** (in addition to the instance.)
+
+For example, if you find yourself passing association proxies as arguments to cached methods, this might be helpful:
+
+ user = User.first
+ Foo.bar(user.groups) # you're passing an association as an argument
+
+ class ActiveRecord::Associations::AssociationCollection
+ # danger! this is a special case... try to use #as_cache_key instead
+ # also note that this example is based on ActiveRecord 3.0.10 ... YMMV
+ def to_cache_key
+ [ proxy_owner.class.name, proxy_owner.id, proxy_reflection.name, conditions ].join('/')
+ end
+ end
+
+Otherwise, `cache_method` will try to run `user.groups.class` which causes the proxy to be loaded. You probably don't want to load 1000 AR objects just to generate a cache key.
+
## Module methods
You can put `#cache_method` right into your module declarations:
View
9 lib/cache_method/cached_result.rb
@@ -16,7 +16,14 @@ def resolve_cache_key(obj)
memo
end
else
- obj.respond_to?(:as_cache_key) ? [obj.class.name, obj.as_cache_key] : obj
+ if obj.respond_to?(:to_cache_key)
+ # this is meant to be used sparingly, usually when a proxy class is involved
+ obj.to_cache_key
+ elsif obj.respond_to?(:as_cache_key)
+ [obj.class.name, obj.as_cache_key]
+ else
+ obj
+ end
end
end
end
View
2  lib/cache_method/version.rb
@@ -1,3 +1,3 @@
module CacheMethod
- VERSION = "0.2.2"
+ VERSION = "0.2.3"
end
View
9 test/helper.rb
@@ -55,6 +55,15 @@ def as_cache_key
end
end
+class CopyCat1b < CopyCat1
+ def as_cache_key
+ raise "Used as_cache_key"
+ end
+ def to_cache_key
+ raise "Used to_cache_key"
+ end
+end
+
module Say
def say_count
@say_count ||= 0
View
7 test/test_cache_method.rb
@@ -317,6 +317,13 @@ def test_as_cache_key
end
end
+ def test_to_cache_key
+ assert_raises(RuntimeError, /Used to_cache_key/) do
+ a = CopyCat1b.new 'mimo'
+ a.echo 'hi'
+ end
+ end
+
def test_method_added_by_extension
assert_equal 'hi', CopyCat2.say('hi')
assert_equal 1, CopyCat2.say_count
Please sign in to comment.
Something went wrong with that request. Please try again.