views:

189

answers:

3

Hello all,

We are creating a system in Ruby on Rails and we want to be able to offer our users a bit of control about notifications and actions that can take place when some pre-defined trigger occurs. In addition, we plan on iterating through imported data and allowing our users to configure some actions and triggers based on that data.

Let me give you a few examples to better clarify:

Trigger                              - Action
------------------------------------------------------------------------
New Ticket is Created                - User receives an e-mail
New Ticket Parsed for Keyword 'evil' - Ticket gets auto-assigned to a
                                       particular group
User Missed 3 Meetings               - A ticket is automatically created

Ideally, we would like some of the triggers to be configurable. For instance, the last example would possibly let you configure how many meetings were missed before the action took place.

I was wondering what patterns might help me in doing this event/callback situation in Ruby on Rails. Also, the triggers and actions may be configurable, but they will be predefined; so, should they be hard coded or stored in the database?

Any thoughts would be greatly appreciated. Thanks!

Update 1: After looking at it, I noticed that the badges system on SO is somewhat similar, based on these criteria, I want to do this action. It's slightly different, but I want to be able to easily add new criteria and actions and present them to the users. Any thoughts relating to this?

A: 

Maybe something like a state-machine can help. Try AASM gem for RoR.

Zepplock
I'm not sure I really see how a state machine could help. Can you please elaborate little bit?
Topher Fangio
Having a state machine is not a solution for callbacks but more of an architectural approach. Define states for "Ticket" class, each state will have a pre- and post- callbacks that get executed for each state change. This eliminates lot's of if/else statements in the code and provides a single point of entry for all "logic" transitions for a particular object.
Zepplock
+1  A: 

You should look at the "callback" methods in Rails

For docs see - Callbacks

Your first rule would be implemented via the after_create method.

If you want them to be configurable, I would suggest using a model / table to store the possible actions and doing a lookup within the callback.

If this is high volume, be sure to consider caching the configuration since it would end up doing a db lookup on each callback.

DrewM
+1  A: 

I think that what you are looking for are the Observers. In your examples the Observers could handle the first and the third example (but not the second one, since an Observer only observes the object, not interact with it, even though it is technically possible).

Some code to show how I mean:

class TicketObserver < ActiveRecord::Observer
  def after_create(ticket)
    UserMailer.deliver_new_ticket_notification
  end
end

class UserObserver < ActiveRecord::Observer
  def after_update(user)
    Ticket.new if user.recently_missed_a_meeting and user.missed_meetings > 3
  end
end

And then add the observers to environment.rb

config.active_record.observers = :user_observer, :ticket_observer

Of course you will have to fill in the logic for the missed_meetings, but one detail to mention. Since the after_update will trigger after every time that the user is being updated, the recently_missed_a_meeting attribute is useful. I usually follow the thinking of restful-authentication and have an instance variable that is being set to true everytime I want to trigger that row. That can be done in a callback or in some custom logic depends on how you track the meetings.

And for the second example, I would put it in a before_update callback, perhaps having the keywords in a lookup table to let users update which words that should trigger the move to a specific group.

Jimmy Stenke
Thanks, this is half of what I was looking for. I would also like people's thoughts on storing and presenting these observers to users. Any ideas there?
Topher Fangio
From what I have understood an Observer is more or less a Model, so having some sort of settings that can be shown to the users and looked up wether they are enabled or disabled.For instance, I usually have a Setting class in my applications which are being called like `UserMailer.deliver_new_ticket_notification if Setting['mailer.new_tickets.enabled']`
Jimmy Stenke
For the last example for instance, instead of having `user.missed_meetings > 3` you could have `user.missed_meetings > Setting['users.allowed_meetings_to_miss']` or even store it in the User model to allow customization per user.
Jimmy Stenke
Thanks for the information. I'll work through it a little bit and post the solution that I use :-)
Topher Fangio