Skip to content
This repository has been archived by the owner on Jan 19, 2023. It is now read-only.

brendantang/auto_alert

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

auto_alert

auto_alert provides a simple DSL to declare conditions that should raise alerts on your ActiveRecord models. Alerts are saved in a database table with a polymorphic association to the model which triggered their creation. It's possible to define different conditions to raise, resolve, and re-raise an alert.

Quick example

Imagine a to-do list application where tasks with a due date in the past should be flagged with an alert. With auto_alert, you can modify your Task model like so:

class Task < ApplicationRecord
  acts_as_alertable

  raises_alert :past_due,
               on: :past_due_date?,
               message: "was due"
               
  private
  def past_due_date?
    due_date < Date.current and !done
  end

Then you can call the scan_for_alerts! on any task and, if past_due_date? returns true, an alert record belonging to that task will be created. Instances of Task will also have a past_due_alert getter method to fetch their associated past_due alert, if any.

Installation

Install auto_alert

Add this line to your application's Gemfile:

gem 'auto_alert'

And then execute:

$ bundle

Create Alert model

auto_alert assumes there is an Alert model to store your alerts in the database.

An appropriate model can be built using the Rails generator by running something like, rails generate model Alert alertable:references resolved:boolean kind:string message:string. Then edit the resulting migration so that it looks like this example.

Make sure to edit the alert model file to register it with auto_alert:

# app/models/alert.rb
class Alert < ApplicationRecord
  acts_as_alert # add this line
end

(In the future I'd like to add an install rake task to automate this process.)

auto_alert assumes the alert relation uses the table called alerts, but you can specify a different relation:

# app/models/task.rb
class Task < ApplicationRecord
  acts_as_alertable # will default to using the Alert model
end

# app/models/task_list.rb
class TaskList < ApplicationRecord
  acts_as_alertable with_table: :special_alerts # will look for a SpecialAlert model
end

Usage

Calling acts_as_alertable in your model definition:

  • Allows you to use the raises_alert class method to declare the conditions that should raise or resolve an alert
  • Registers that model instances have alerts
    • Uses polymorphic association, so you can use all the instance methods it provides
    • Also creates convenience getters for each kind of alert that model can raise (i.e. task.past_due_alert)
  • Provides the instance method scan_for_alerts!, which creates or updates alert records according to the declared raises_alert conditions.

Scanning for alerts

auto_alert makes no assumptions about when you'd like to check if alerts should be raised or resolved.

For simple use cases, it can make sense to call scan_for_alerts! on specific instances from your controller, or to hook into one of the ActiveRecord callbacks:

class MyModel < ApplicationRecord
  acts_as_alertable
  # ...
  after_save :scan_for_alerts!

For more complicated use cases, especially where alert conditions rely on factors external to the model instance itself, it can make sense to use a job to asynchronously call scan_for_alerts! on big batches of records.

You can also call the class method scan_all_unresolved! on your Alert model to check if any unresolved alerts should be resolved. Again, it might be best to use a job to do this periodically in the background.

Alert records

auto_alert assumes there is an ActiveRecord model for the table alerts, with at least:

  • A polymorphic alertable reference (pointing to the record which triggered the alert)
  • A boolean resolved attribute (indicating the alert is no longer relevant)
  • A kind attribute (each alertable record has only one alert of each kind—past_due in the example above)
    • Can be a text column or a Rails enumerable using a numeric column (example)
  • A string message attribute describing the alert details

Instructions for creating such a model are in the Installation secion under Create Alert model.

Declaring rules to raise and resolve alerts

The on parameter to raises_alert can take a method name as above, or a proc:

raises_alert :past_due, 
  on: ->(t) { t.due_date < Date.current and !t.done }

You can also pass a resolve_on parameter to specify the condition for marking the alert resolved. A proc or method name is acceptable.

class Order < ApplicationRecord
  acts_as_alertable

  raises_alert :week_old,
    on: ->(order) { order.placed <= Date.current - 1.week },
    resolve_on: :shipped 
    # Now changing the order date won't resolve the alert, but marking it `shipped` will.

If no resolve_on parameter is passed, the inverse of the on condition is used.

Re-raising alerts

By default, an alert which is resolved will not be re-raised, even if the on condition is met again. If you pass the reraise option true, the alert's resolved attribute will be updated to false every time the on condition is met.

class Temperature < ApplicationRecord
  acts_as_alertable
  
  raises_alert :too_cold,
    on: ->(temp) { temp.farenheit < 32 },
    reraise: true

You can also give a proc or method name to the reraise option to use a condition other than the initial on condition.

Messages

Alert messages can be built using a string, a proc, or a method name. When an alert is re-raised, its message will be built again.

License

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

About

A plugin for Rails which makes it easy to specify conditions to raise or resolve alert records associated with your ActiveRecord models

Topics

Resources

License

Stars

Watchers

Forks