Ledger

Does your app have the concept of accounts, with multiple users per account?

Yes?

Great.

Ledger will easily allow you to create an activity stream of user events on a per account basis.

Installation

Add this line to your application's Gemfile:

gem 'ledger'

And then execute:

$ bundle

Or install it yourself as:

$ gem install ledger

Usage

Start by adding the HasEvents module to your account object.

class Accounts
    
    include Ledger::HasEvents
    
end

Add in the CreatesEvents module to your controller.

class CategoriesController
    
    include Ledger::CreatesEvents
    
end

Now all you need to do is call #create_event when you do something.

def update
    @category.update_attributes! params[:category]
    create_event :updated, @category
end

Retrieve your event stream like so

.event_stream.each do |e|
    puts "#{a.actor['name']} #{a.action} #{a.object} #{a.data['name']}"
end
"Mal Curtis updated Category Food"

#event_stream brings back the last 10 events. Send through an integer to get more.

Each event has the following (by default, for options see further down).

{
    "action"=>"updated",
    "object"=>"Category",
    "actor"=>{
        "id"=>1,
        "email"=>"[email protected]",
        "name"=>"Mal Curtis"
    },
    "data"=>{
        "id"=>1515,
        "name"=>"Food"
    },
    "created_at"=>2013-03-03 09:28:59 +1300
}

Ledger isn’t opinionated about how you display your events in your app. You’ll need to figure that one out.

Customizing

Accounts & Users

Ledger expects there to be a current_account and current_user method when creating an event. If this doesn’t suit your app, smash this into an initializer.

Ledger.configure do |config|
    config.event_scope_method = :current_account # Or whatevs
    config.event_actor_method = :current_user # as above
end

Moar object data

Ledger will try and add id, email and name from your user object and id and name from the object passed to #create_event. If you don’t have some of these methods, or want to add more information, just define #event_details and return a hash.

class User
    include Ledger::HasEvents
    def event_details
        { id: id, email: email, username: username }
    end
end

class Category
    def event_details
        { id: id, parent: parent_id, description: description }
    end
end

Moar event data

Want to send more information about events? Just send through the information at the end of the #create_event call.

create_event :state_changed, @category, from: from_state, to: @category.state
{
    "action"=>"state_changed",
    "object"=>"Category",
    "actor"=>{
        "id"=>1,
        "email"=>"[email protected]",
        "name"=>"Mal Curtis"
    },
    "data"=>{
        "id"=>1515,
        "name"=>"Food",
        "from"=>"available",
        "to"=>"unavailable"
    },
    "created_at"=>2013-03-03 09:28:59 +1300
}

Redis connection

Ledger defaults to $redis. If you want to set this manually, customize it in an initializer. Here's an example:

Ledger.configure do |config|
    uri = URI.parse(ENV["REDISTOGO_URL"] || 'redis://127.0.0.1:6379')
    config.redis = Redis.new(
        :host => uri.host,
        :port => uri.port,
        :password => uri.password
    )
end

Manual Events

You can add an event manually by creating an instance of Ledger::Event, then adding that in via account.add_event.

new_event = Ledger::Event.new action: "create", object: "manual_event", data: { some: "thing" }
.add_event new_event

Direct Redis access

You can access redis directly through #events. This will be a Nest instance and you can call on it, or use its naming schema to do some other magic.

# Trim the events down to the last 100 events
.events.ltrim 0, 100

# Create a new redis key (account:xxx:events:something_else)
.events["something_else"].lpush "Some data"

Who

Created with love by Mal Curtis

Twitter: snikchnz

License

MIT. See license file.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request