Build Status Maintainability Test Coverage

Beholders

A lightweight implementation of the observer pattern for rails active record models.

Originally developed as an alternative to rails-observers with the goal of:

  • Better support for current versions of rails.
  • Encourage the single responsibility principle in design- beholders are explicitly added by name to a model, rather than inferred based on its name. This lets you have multiple observers each named for their specific domain.

Supports rails 4.0+ (tested up to 5.1).

Installation

Add this line to your application's Gemfile:

gem 'beholders'

And then execute:

$ bundle

Or install it yourself as:

$ gem install beholders

Usage

Getting started example:

# Observers are added to a model like:
class Train < ApplicationRecord
  observed_by "TimelineManager"
  observed_by "PlatformAnnouncer"
  observed_by "Planner::RisksCacher"
end

# Your observers inherit from Beholder
class TimelineManager < Beholder
  # Define public methods for each callback hook you want to trigger on
  # They should accept 1 arg, the instance of an observed model
  def after_create_commit(subject)
    TimelineEntry.create!(subject: subject)
  end
end

class PlatformAnnouncer < Beholder
  def after_update_commit(subject)
    return unless subject.previous_changes.include? :arrival_time
    # broadcast an event to your action cable channel
  end
end

ActiveRecord::Base class methods:

Class names are passed as a string to prevent redundant autoloading.

observed_by "BeholderClassName"

Callback hooks:

Define as public methods with a single argument (model instance) in your beholders to trigger during that callback stage of the model.

after_save
after_create
after_update
after_destroy

after_commit
after_create_commit
after_update_commit
after_destroy_commit

Beholders are enabled by default and can be disabled/enabled individually and globally, which is probably most useful for test isolation. The following class methods are available:

class MyBeholder < Beholder; end

MyBeholder.disable!  # disable MyBeholder
MyBeholder.disabled? # true
MyBeholder.enable!   # enable MyBeholder
MyBeholder.disabled? # false

Beholder.disable_all! # disable Beholder and all descendant classes
Beholder.enable_all!  # enable Beholder and all descendant classes

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec 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 rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/Bogadon/beholders. 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.

License

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

Code of Conduct

Everyone interacting in the Beholders project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.