0

I'm working on a web app where people can save records using an industry-specific taxonomy. Most of my users will be familiar with it, but some may not be, or they may be rusty... etc.

I have some required fields in these records where I'd like to give people the option to select: "I don't know." However, I don't want the database to be full of lazy "I don't know" entries, so I'd like to limit each user to marking "I don't know" only a few times per day.

In addition, I have moderators on the site who will go back and look at entries filed "I don't know." I'd like for the moderators to be notified of any new "I don't know" answers whenever they log in to the site so they can take a look and correct the record.

Lastly, I'd like for users whose records have been corrected to be notified when they login that their record was updated. In this way they can go back and see how they should have filed their record.

What I really want to know is:

  1. Does this kind of problem follow a specific pattern that you're aware of? (IE: is there a term I could Google that would point me to good resources about how to handle this kind of situation)
  2. Are you're aware of some good reading / tutorials that might be helpful.
  3. Most importantly, can you offer some guidance as to how to solve this problem in the "Rails way"?

Thanks!

-EDIT- To add some clarity to what I'm really hoping for: If you had this kind of need on your site, how would you solve it? Would you use an observer? Do you make an attribute in the model and have the observer "manipulate" that, or do you keep all the code in the observer. Is there a different way to solve this problem?

Really I just have no idea how to approach this, and I'd very much value any feedback you all can give as to how you would think about this kind of problem and an outline of how you might solve it.

I'm aware that I can use Observers as part of the solution, but I don't really know the best way to tell an observer to notice if something has happened three times in 24 hours... that kind of thing, or to know whether or not someone has read a notification.

Thanks!

Andrew
  • 42,517
  • 51
  • 181
  • 281
  • Just to let people know, since the bounty lasts 6 days and since I really don't have solid previous knowledge of this subject, I'm going to keep the question open longer than I normally do -- at least another 2-3 days -- while I do some testing etc. Please continue to post thoughts / answers if you've got any! – Andrew Jan 27 '11 at 23:12

5 Answers5

1

Can't you use an active record observer to do this? The Ruby on Rails guide has some examples of how to use them.

tjwallace
  • 5,528
  • 1
  • 26
  • 15
picardo
  • 24,530
  • 33
  • 104
  • 151
  • Well, this is what I'm asking! I've never worked with observers before, so is there a good tutorial you can point me to? Should I make a new model specifically for displaying notifications from the observer, or can I tie it into the flash or something? That's why I asked the question in the first place :) – Andrew Jan 24 '11 at 00:04
  • In other words... help me understand how. I don't get it (yet). – Andrew Jan 24 '11 at 00:05
1

I believe what you're describing here is essentially "workflow." For an academic approach see:

http://www.workflowpatterns.com/patterns/control/index.php

But that can get really complicated. I think it's better to try to solve problems simply.

For your user/moderator save scenarios, I recommend reading about callbacks:

http://edgeguides.rubyonrails.org/active_record_validations_callbacks.html#available-callbacks

For example, you could use the 'after_create' callback to do something when a user initially saves a record, and the 'after_update' callback when a moderator or user updates the record (you might add a condition to determine which user type is updating the record, and respond accordingly). ['after_save" covers both the creating and updating cases.]

In your views, you might allow the user to filter by record state. For example, a user might want to view all reviewable records or only those records which have been reassigned to them by a moderator. Based on the status of a record you might alert the user visually (e.g., highlight a row).

This isn't unlike a bug tracker. Bugs entered into the system may be unassigned initially and acquired by a programmer user, or assigned to the programmer from the start. The programmer makes a fix, updates the status and then another user type, such as a tester, may need to review the fix. If the bug wasn't fixed the tester may reassign the item to the programmer.

That's workflow.

Regarding the "I don't knows," you could implement that as a counter, but you'll also need to track the date so you can reset it daily using a schedule task, or by some user event such as a login.

TK-421
  • 10,598
  • 3
  • 38
  • 34
1

To pile on (in a little more detail)

1) Use custom validation, where you check the user_id, the answer & the updated_at. If the answer "I don't know" appears more that X number of times where updated_at > 1.day.ago ... have it fail validation

2) You will need "persistent flash messaging". This mean that you will need to FlashMessage model where you store the messages to display to the users on login. It will need the following fields: user_id, message, is_read(boolean)

3) Lastly, you will need an observer on the table that has the validator (mentioned in point 1). That observer will write to the flash_messages table "after_create"

Aaron Scruggs
  • 712
  • 1
  • 4
  • 10
  • This is very helpful -- particularly your example #1 and the keywords "persistent flash messaging" which is a big help on Google :) I'll try some experiments... – Andrew Jan 27 '11 at 20:55
0
class YourObserver < ActiveRecord::Observer
   observe :model_to_observe

   # an example of callback
   def after_save(model_to_observe)
      #some stuff to check and do
   end
end

and in your application.rb

config.active_record.observers = :you_observer

Cheers

Pasta
  • 1,750
  • 2
  • 14
  • 25
  • Thanks Pasta, this is good reference code to have associated with this post. However, what this doesn't answer is: would you use observers to solve a problem of wanting to limit a user action to three occurrences per day? – Andrew Jan 27 '11 at 14:39
0

Let's assume that you are monitoring the quality of a field called category in your Book model.

Add an observer(data_quality_observer.rb) in your models directory.

class DataQualityObserver < ActiveRecord::Observer
   observe :book  
   def after_save(book)
     book.process_incomplete_category
     book.process_complete_category
   end
end

Register the observer in config\environment.rb

Rails::Initializer.run do |config|
  # ..
  # ..
  config.active_record.observers = :data_quality_observer
end

Book model:

class Book
  INCOMPLETE_CATEGORY = "I don't know."

  def complete_category?
    category != INCOMPLETE_CATEGORY
  end

  def process_incomplete_category
    return if complete_category?

    k = Book.count(
      :conditions => ["user_id = ? AND category = ? AND updated_at > ?", 
        self.user_id, INCOMPLETE_CATEGORY, 1.day.ago]
    )

    UserMailer.deliver_incomplete_category_notification(self)  if ( k > 3)    
  end

  # if the category became complete
  def process_complete_category
    return unless complete_category?
    return unless (category_was == INCOMPLETE_CATEGORY)

    # do additional check to ensure admin did the changes
    UserMailer.deliver_complete_category_notification(self)
  end

end

Add a mailer to notify admins of incomplete categories and users of corrected categories

class UserMailer < ActionMailer::Base

  def incomplete_category_notification(book)
    from        "bot@domain.com"
    sent_on     Time.now      
    recipients  "admin@domain.com"
    body        :book => book   
    subject     "User #{book.user.name} has entered 3 incomplete categories"    
  end

  def complete_category_notification(book)
    from        "bot@domain.com"
    sent_on     Time.now      
    recipients  book.user.email
    body        :book => book   
    subject     "The category field was updated for a record you created"    
  end

end
Harish Shetty
  • 64,083
  • 21
  • 152
  • 198
  • This line `k = Book.count( :conditions => ["user_id = ? AND category = ? AND updated_at > ?", self.user_id, INCOMPLETE_CATEGORY, 1.day.ago] )` is the meat of your answer... that's very, very helpful and a new idea to me. Thanks! – Andrew Jan 27 '11 at 23:13
  • Kandada, thank you very much for your long answer. I think the best answer is a combination of yours and Aaron Scruggs, and because they both were equally helpful I decided to award him the bounty since he has 10,000 less reputation than you :) Thank you so much for your very thorough example, though! – Andrew Jan 29 '11 at 14:47