{"id":23869464,"url":"https://github.com/fredwu/bustle","last_synced_at":"2025-08-26T20:10:44.782Z","repository":{"id":3555153,"uuid":"4616173","full_name":"fredwu/bustle","owner":"fredwu","description":"Activities recording and retrieving using a simple Pub/Sub-like interface.","archived":false,"fork":false,"pushed_at":"2013-11-07T22:31:00.000Z","size":258,"stargazers_count":93,"open_issues_count":3,"forks_count":8,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-09T05:06:11.107Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://fredwu.github.com/bustle/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fredwu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-06-10T15:42:07.000Z","updated_at":"2023-02-21T06:53:27.000Z","dependencies_parsed_at":"2022-07-28T21:19:05.049Z","dependency_job_id":null,"html_url":"https://github.com/fredwu/bustle","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fredwu%2Fbustle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fredwu%2Fbustle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fredwu%2Fbustle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fredwu%2Fbustle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fredwu","download_url":"https://codeload.github.com/fredwu/bustle/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fredwu%2Fbustle/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259146618,"owners_count":22812279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-03T12:35:03.676Z","updated_at":"2025-06-10T20:35:16.531Z","avatar_url":"https://github.com/fredwu.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bustle [![endorse](http://api.coderwall.com/fredwu/endorsecount.png)](http://coderwall.com/fredwu) [![Build Status](https://secure.travis-ci.org/fredwu/bustle.png?branch=master)](http://travis-ci.org/fredwu/bustle) [![Dependency Status](https://gemnasium.com/fredwu/bustle.png)](https://gemnasium.com/fredwu/bustle) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/fredwu/bustle)\n\nActivities recording and retrieving using a simple Pub/Sub-like interface.\n\nThe typical use cases are:\n\n- Timeline (e.g. tracking activities such as posting and commenting for users)\n- Logging\n\nThe advantages of Bustle are:\n\n- It is lightweight and simple to use\n- It is largely self-contained and separated from you core app logic\n- It works nicely with ActiveRecord out of box\n- It is ORM-agnostic therefore can be extended to use with other databases\n- It has full unit test coverage\n\nBustle is built for simplicity and extensibility. If you are after high performance pub/sub then this gem is not for you.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'bustle'\n```\n\n## Usage\n\n### Configuration\n\nFirst of all, you will need to configure Bustle. If you are using Rails, you can put the following code in an initializer (e.g. `config/initializers/bustle.rb`).\n\n```ruby\nBustle.config do |c|\n  # Specify a storage strategy for storing activities\n  # Bustle ships with an ActiveRecord storage strategy\n  c.storage = Bustle::Storage::ActiveRecord\nend\n```\n\nFor ActiveRecord, you will need the following migration file:\n\n```ruby\nclass CreateBustleTables \u003c ActiveRecord::Migration\n  def change\n    create_table :bustle_activities do |t|\n      t.string  :resource_class\n      t.integer :resource_id\n      t.string  :action,       :default =\u003e ''\n      t.text    :data,         :default =\u003e ''\n      t.integer :publisher_id, :null =\u003e false\n      t.timestamps\n    end\n\n    create_table :bustle_publishers do |t|\n      t.string  :resource_class, :null =\u003e false\n      t.integer :resource_id,    :null =\u003e false\n      t.timestamps\n    end\n\n    create_table :bustle_subscribers do |t|\n      t.string  :resource_class, :null =\u003e false\n      t.integer :resource_id,    :null =\u003e false\n      t.timestamps\n    end\n\n    create_table :bustle_subscriptions do |t|\n      t.integer :publisher_id,  :null =\u003e false\n      t.integer :subscriber_id, :null =\u003e false\n      t.timestamps\n    end\n\n    add_index :bustle_activities, :publisher_id\n    add_index :bustle_publishers, [:resource_class, :resource_id], :unique =\u003e true\n    add_index :bustle_subscribers, [:resource_class, :resource_id], :unique =\u003e true\n    add_index :bustle_subscriptions, :publisher_id\n    add_index :bustle_subscriptions, :subscriber_id\n    add_index :bustle_subscriptions, [:publisher_id, :subscriber_id], :unique =\u003e true\n  end\nend\n```\n\n### Flow\n\nUpon subscribing:\n\n1. Subscriber registers itself if not already registered\n2. Publisher registers itself if not already registered\n3. A Subscription is created for Subscriber and Publisher\n\nWhen activities occur:\n\n1. Publisher registers itself if not already registered\n2. Publisher publishes activity\n\n### API\n\n#### Register a Subscriber\n\n```ruby\n# returns a subscriber instance upon duplicated entry\nBustle::Subscribers.add subscriber\n# raises error upon duplicated entry\nBustle::Subscribers.add! subscriber\n\n# example\nuser = User.find(1)\nBustle::Subscribers.add user\n```\n\n#### Register a Publisher\n\n```ruby\n# returns a publisher instance upon duplicated entry\nBustle::Publishers.add publisher\n# raises error upon duplicated entry\nBustle::Publishers.add! publisher\n\n# example\npost = Post.find(1)\nBustle::Publishers.add post\n```\n\n#### Create a Subscription\n\n```ruby\n# returns a subscription instance upon duplicated entry\nBustle::Subscriptions.add bustle_publisher, bustle_subscriber\n# raises error upon duplicated entry\nBustle::Subscriptions.add! bustle_publisher, bustle_subscriber\n\n# example\npublisher  = Bustle::Publishers.get(Post.first)\nsubscriber = Bustle::Subscribers.get(User.first)\nBustle::Subscriptions.add publisher, subscriber\n```\n\n#### Find a Subscriber/Publisher/Subscription\n\n```ruby\nBustle::Subscribers.get subscriber\nBustle::Publishers.get publisher\nBustle::Subscriptions.get bustle_publisher, bustle_subscriber # =\u003e Bustle::Subscription\nBustle::Subscriptions.by bustle_publisher # =\u003e an array of Bustle::Subscription by the publisher\nBustle::Subscriptions.for bustle_subscriber # =\u003e an array of Bustle::Subscription for the subscriber\n```\n\n#### Remove a Subscriber/Publisher/Subscription\n\n```ruby\nBustle::Subscribers.remove subscriber\nBustle::Publishers.remove publisher\nBustle::Subscriptions.remove bustle_publisher, bustle_subscriber\n# or use `remove!` to raise an exception if the resource cannot be found\n```\n\nOr:\n\n```ruby\nBustle::Subscribers.get(subscriber).destroy\nBustle::Publishers.get(publisher).destroy\nBustle::Subscriptions.get(bustle_publisher, bustle_subscriber).destroy\n```\n\n#### Find Referenced Resources\n\nThese are helpful for finding referenced resources.\n\n```ruby\nBustle::Activity#publisher_resource\nBustle::Activity#target_resource\nBustle::Publisher#target_resource\nBustle::Subscriber#target_resource\nBustle::Subscription#publisher_resource\nBustle::Subscription#subscriber_resource\n```\n\n#### Publish an Activity\n\n```ruby\nBustle::Activities.add bustle_publisher, {\n  :resource =\u003e some_resource,\n  :action   =\u003e some_string,\n  :data     =\u003e some_text\n}\n# or\nBustle::Publisher.publish({\n  :resource =\u003e some_resource,\n  :action   =\u003e some_string,\n  :data     =\u003e some_text\n})\n\n# example\npost    = Post.find(1)\ncomment = post.comments.add(:content =\u003e \"I'm a comment\")\nBustle::Publishers.add post\npublisher = Bustle::Publishers.get post\npublisher.publish({\n  :resource =\u003e comment,\n  :action   =\u003e 'new',\n  :data     =\u003e 'useful for putting serialized data or JSON here'\n})\n```\n\n#### Activities\n\n##### Retrieve Activities for a Subscriber\n\n```ruby\nBustle::Activities.for bustle_subscriber\n# or\nBustle::Subscriber.activities\n\n# example\nsubscriber = Bustle::Subscribers.get(User.first)\nsubscriber.activities\n```\n\n##### Retrieve Activities by a Publisher\n\n```ruby\nBustle::Activities.by bustle_publisher\n# or\nBustle::Publisher.activities\n\n# example\npublisher = Bustle::Publishers.get(Post.first)\npublisher.activities\n```\n\n#### Filtering (for Activities and Subscriptions)\n\n```ruby\nBustle::Activities.filter :key =\u003e :value\nBustle::Subscriptions.filter :key =\u003e :value\n# or\nBustle::Subscriber.activities :key =\u003e :value\n\n# example\nsubscriber = Bustle::Subscribers.get(User.first)\nsubscriber.activities :action =\u003e 'new'\n```\n\n## License\n\nThis gem is released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).\n\n## Author\n\n[Fred Wu](https://github.com/fredwu), originally built for [500 Startups](http://500.co).\n\n\n[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/fredwu/bustle/trend.png)](https://bitdeli.com/free \"Bitdeli Badge\")\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffredwu%2Fbustle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffredwu%2Fbustle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffredwu%2Fbustle/lists"}