Merb caching DataMapper
Monday, 05 January 2009Strange the evolution of Merb: copy what Rails does; reinvent how Rails does it; assimilate into Rails. Hopefully Rails will become as easy to hack as Merb is currently.
Case in point: Merb::Cache. It’s first iteration was nearly a direct clone of Rails caching, complete with fragment, action, and page caching. Then the core team had to get clever and reinvent the wheel. While a little half baked, it provides a foundation for constructing almost any type of cache, and is ripe for documentation!
There are several hurdles to get over to start using Merb::Cache:
- It isn’t intuitive. Or at least not for someone who is used to the Rails way. Fortunately, all of it doesn’t have to make sense in order be useful.
- It doesn’t play well with DataMapper. Or rather DataMapper doesn’t play nice, unless dm-core edge is used.
- It doesn’t work out of the box. The file cache, in particular, doesn’t do anything to serialize what is being cached, and no strategy is provided to do the work.
Preparation:
Working backwards, these hurdles are easy to clear. First, create a new strategy to serialize what is being cached. Using the gzip_store as a model, it’s easy to create a marshal_store that uses Marshal.dump and Marshal.load to serialize and deserialize any data that is being cached. This file can be placed in the lib folder for safe-keeping.
Setup:
Merb::Cache should be included in the Merb stack. If not, make sure that there is a dependency set for merb-cache. At the same time, add a dependency for dm-serializer (from dm-more); this is required to serialize DataMapper objects.
[code] # somewhere in the init.rb or dependencies.rb file dependency merb-cache dependency dm-serializer [/code]
It is easiest to configure Merb::Cache in an after_app_loads block in each environment file, since the caching schemes across environments will differ. Production will use a file cache store, while the other environments will use an adhoc store which does nothing.
[code] # in config/environments/production.rb Merb::BootLoader.after_app_loads do require 'lib/marshal_store' Merb::Cache.setup do # FYI, you can check whether a cache store has been setup with # Merb::Cache.stores.has_key?(:file_cache) register(:base_cache, Merb::Cache::FileStore, :dir => "tmp") register(:file_cache, Merb::Cache::MarshalStore[:base_cache]) end end [/code]
[code] Merb::BootLoader.after_app_loads do Merb::Cache.setup do register(:file_cache, Merb::Cache::AdhocStore.new) end end [/code]
Caching can now easily be used wherever needed:
[code] # for example, in a controller or model cache = Merb::Cache[:file_cache] keys = ['users',params] if cache.exists?( *keys ) @users = cache.read( *keys ) else cache.write( keys.first, @users = User.all, keys.last ) end [/code]
NOTE: the cache will have to be expired manually, since the file cache does not support time-based expiration.
[code] Merb::Cache[:file_cache].delete( *keys ) [/code]
Conclusion:
This solution should keep you warm and toasty for the next 6 months until Merb 2 / Rails 3 comes out. In the meantime, let’s get behind a Franken-source project we can all believe in: the integrity of ActiveRecord and the concept of DataMapper (ActiveDataRecordMapper? ActivataRecapper?)
Comments