views:

49

answers:

3

Alright here's the trickiest question I've ever had to ask on StackOverflow.

My Web App allows creating a document. This document is automatically saved lets say ever couple of seconds.

Meanwhile, I want a news feed to lets users know what there friends are up to. So I created a observer model which after_create creates a news_feed type item.

Problem is this observer as is now will create a news_feed on ever save which is a huge firehose.

So I want to make it so the news_feed for this model is only injects per session or every X minutes. So I added a last_feeded_at column to the model.

Problem is when I try to update that field in the observer to mark it was feeded, that triggers the observer, which makes a mess of everything.

What's the best way to handle this? I'm open to all smart suggestions.

Thanks

A: 

I'd create your NewsFeed object using this kind of logic

def find_or_create_feed
  if session[:news_feed].nil?
    NewsFeed.new
  else
    NewsFeed.find(session[:news_feed])
  end
end

that way, you can return the same NewsFeed object for an entire session. If you want to get fancy and expire it, do a sweep of the news_feeds table periodically to remove feeds over a given age.

Steve Ross
@ Steve, thanks, but where would this live? Can you give a little more context around the use case? real excited to learn a smarter way to do what I'm trying to do. My code is getting messy! thanks
AnApprentice
Well, it's your app, but I assume you have a controller that, from what you describe, handles the user interaction around creating and editing a document. Again, just from your description, it would seem you want to create a news feed when the document is accessed for the first time in a given session. So, I guess I would say hit it in a before_filter and assign the result to an instance variable so your view can display it. Or... it's possible I've missed your intent for this feature.
Steve Ross
The controller should only perform 1 action on a model, e.g. save an update for Document. The Document model should then perform whatever dependent actions there are.
Ariejan
@Ariejan: Although you can strive to observe the LoD, controllers are constantly making information from disparate models -- sometimes unrelated -- available to their views. I would advocate for clarity of code.
Steve Ross
+1  A: 

I would not add an attribute to you Document model for this. You probably have something like this already:

class Document
  has_many :news_feeds, :order => 'created_at DESC'
end

In your callback (in Document model), just check when the last news_feed was created:

after_save :create_news_feed, :if => Proc.new { |doc| doc.news_feeds.first.created_at <= 10.minutes.ago }

This will only call create_news_feed if the last news_feed was created at least 10 minutes ago.

Ariejan
Just noticed your session requirement. Add an `attr_accessor :session_id` to your Document model and store that value with each new_feed record you create. Update the `:if` statement accordingly.
Ariejan
The OP wanted a news feed per session. Why not base the creation of the news feed on session rather than age?
Steve Ross
Interesting, I was trying to do all this in the OBserver to keep it isolated.
AnApprentice
+1  A: 

I assume that when the user finishes editing they perform a final save? Define a attr_accessor, draft, which is sent as a parameter from the controller when handling request.js ajax saves. I don't see need for an observer really; just put it in the model.

attr_accessor :draft
after_save :log_unless_draft

def log_unless_draft
  unless draft.eql?(true)
    log_event.new(...

By the way, I don't understand why after_create is even triggering, given these aren't new_record?s beyond the first save.

mark
To add a little more color. When a user clicks New Note, a Note is created and then the user is redirected to the note to start typing.. I don't want a news feed item at that time bec the Note Title has not yet been set. Which is why I only want to feed it once the title is note Untitled....
AnApprentice
Also, there is no final save, it's more like Google Docs, the note is auto saving to the server (DEF UPDATE) on a timer and based on user activity. It's those saves that are flooding the feed and which I want to manage. Does that make sense?
AnApprentice
Makes sense about the flooding though google docs does have a (final) save button; personally I think it would be bad interface design not to. Users will expect to save when they're finished and this would be the ideal time to log to the feed.
mark