Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


The best thing to happen since bottled water

Wait, wasn't that bottled_decorators?, or was it bottled_services?, I am starting to lose track. Anyway! bottled_observers are an easy-to-use solution, for the Observer / Subscribe-Publish pattern in ruby. all you need to worry about is adding your business logic, let bottled_observers handle the rest!


Add this line to your application's Gemfile:

gem 'bottled_observers'

And then execute:

$ bundle

Or install it yourself as:

$ gem install bottled_observers


bottled_observers has two main modules you need to be aware of; BottledObserver and BottledObservable.


This module should be included in your observer class, and that observer class should only contain a single public method: #call.

class SendPushNotification
  include BottledObserver # <-- just like this!
  def call
    # Some intense and awesome logic to notify the hell out of them users.

That is all there is to it, your observer is now ready to rock'n'roll.


This module is included in any class that should allow observers to subscribe to it.

class Product
  include BottledObservable # <-- and just like this!
  # The rest of the class....

And that is it, your whole bottled_observers subscribe/publish cycle is ready to go.

The Subscribe / Publish Cycle

There are three main methods available in your arsenal that you need to be aware of:

  • #add_subscription
  • #modified
  • #publish

These are available to your observable class instances, so if we wanted to subscribe our SendPushNotification observer to an instance of our Product class, we could do the following:

@product = Product.find(1)                     # <-- instantiate Product from a record in the database. 
@product.add_subscription SendPushNotification # <-- add a subscription for the SendPushNotification class

We now have a SendPushNotification observer lying in wait for any publications from the @product instance.
Then, when we want to notify the observer(s) of any changes to the instance, just set the state of the instance as modified using the #modified method, and publish this change of state to its subscribers:

Example case: sending push notifications after a successful save of the @product instance.

# The product is only in a modified state if the save is successful
@product.modified if
# If the @product's state is 'modified' the observers call method will be excecuted. 
# If the state is not modified, nothing will happen.

Super simple!

Another thing that needs to be noted is, after publishing, the instances modified state is reset, so to publish anything again, it must be set again.

@product.publish # <-- push notifications sent.
@product.publish # <-- push notifications not sent.
@product.publish # <-- push notifications sent.
@product.publish # <-- push notifications sent.


You can have as many observers subscribed to a single instance as you like:

@product.add_subscription SendPushNotification
@product.add_subscription MailToMailingList
@product.add_subscription CreateRecentActivityRecord

@product.modified if

#subscriptions will return an array of current observer instances subscribed to the observable instance:

@product.add_subscription SendPushNotification
@product.subscriptions #=> [#<SendPushNotification:0x00...>]

To remove observers of a particular class, use #remove_subscription:

@product.add_subscription SendPushNotification
@product.subscriptions #=> [#<SendPushNotification:0x00...>]
@product.remove_subscription SendPushNotification
@product.subscriptions #=> []

Or use #remove_subscriptions (notice the plural) to, you guessed it, remove all observers:

@product.add_subscription SendPushNotification
@product.add_subscription MailToMailingList
@product.add_subscription CreateRecentActivityRecord
@product.subscriptions #=> [#<SendPushNotification:0x00...>, ...]

@product.subscriptions #=> []

You can also check if your product is in a modified state by checking if it is #publishable?:

@product.publishable? #=> false
@product.publishable? #=> true


After checking out the repo, run bin/setup to install dependencies. Then, run rspec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to


Bug reports and pull requests are welcome on GitHub at This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.


The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the BottledObservers project’s codebases, issue trackers, chat rooms and mailing lists is expected to have a beer or two before and enjoy life. Oh yeah and apparently this too: code of conduct.


My own gem implentation of the Observer / Subscribe - Publish design pattern for use in my projects, and for anyone else who wishes to use it.



Code of conduct


No releases published


No packages published