module Redcrumbs

Redcrumbs uses `dirty attributes` to track and store changes to ActiveRecord models in a way that is fast and
unobtrusive. By storing the data in Redis instead of a SQL database the footprint is greatly reduced, no
schema changes are necessary and we can harness all the advantages of a key value store; such as key expiry.

Author:: John Hope
Copyright:: Copyright (c) 2014 John Hope for Project Zebra
License:: MIT License (http://www.opensource.org/licenses/mit-license.php)

To start tracking a model use the 'redcrumbed' method:

  class Venue
    redcrumbed, :only => [:name, :latlng]

  has_one :creator, :class_name => ‘User’

  end

  venue = Venue.last
  venue.crumbs(:limit => 20)
  crumb = venue.crumbs.last
  crumb.creator
     => #<User ... >
  crumb.modifications
     => {"name"=>["Belfast City Hall", "The City Hall, Belfast"]}

See the documentation for more details on how to customise and use Redcrumbs.

Constants

VERSION

Public Class Methods

crumb_class() click to toggle source

Constantises the class_name attribute, falls back to the Crumb default.

# File lib/redcrumbs/config.rb, line 30
def self.crumb_class
  if @@class_name and @@class_name.length > 0
    constantize_class_name
  else
    Crumb
  end
end
included(base) click to toggle source
# File lib/redcrumbs.rb, line 54
def self.included(base)
  base.extend(ClassMethods)
end
redis=(server) click to toggle source

Stolen from resque. Thanks! Accepts:

1. A 'hostname:port' String
2. A 'hostname:port:db' String (to select the Redis db)
3. A 'hostname:port/namespace' String (to set the Redis namespace)
4. A Redis URL String 'redis://host:port'
5. An instance of `Redis`, `Redis::Client`, `Redis::DistRedis`,
   or `Redis::Namespace`.
# File lib/redcrumbs/config.rb, line 48
def self.redis=(server)
  case server
  when String
    if server =~ /redis\:\/\//
      redis = Redis.connect(:url => server, :thread_safe => true)
    else
      server, namespace = server.split('/', 2)
      host, port, db = server.split(':')
      redis = Redis.new(:host => host, :port => port,
        :thread_safe => true, :db => db)
    end
    namespace ||= :redcrumbs

    @@redis = Redis::Namespace.new(namespace, :redis => redis)
  when Redis::Namespace
    @@redis = server
  else
    @@redis = Redis::Namespace.new(:redcrumbs, :redis => server)
  end

  setup_datamapper!

  @@redis
end
setup() { |self| ... } click to toggle source
# File lib/redcrumbs.rb, line 50
def self.setup
  yield self
end

Private Class Methods

constantize_class_name() click to toggle source
# File lib/redcrumbs/config.rb, line 95
def self.constantize_class_name
  klass = @@class_name.to_s.classify.constantize

  unless klass < Redcrumbs::Crumb
    raise ArgumentError, 'Redcrumbs crumb_class must inherit from Redcrumbs::Crumb'
  end

  klass
rescue NameError
  Crumb
end
setup_datamapper!() click to toggle source

Note: Since it’s not possible to access the exact connection the DataMapper adapter uses we have to use the @@redis module variable and make sure it’s consistent.

# File lib/redcrumbs/config.rb, line 78
def self.setup_datamapper!
  adapter = DataMapper.setup(:default, 
    { :adapter  => "redis", 
      :host => self.redis.client.host, 
      :port => self.redis.client.port, 
      :password => self.redis.client.password
    })

  # For supporting namespaces:
  #
  adapter.resource_naming_convention = lambda do |value|
    inflected_value = DataMapper::Inflector.pluralize(DataMapper::Inflector.underscore(value)).gsub('/', '_')

    "#{self.redis.namespace}:#{inflected_value}"
  end
end