3

I have an app that needs to periodically update a "news" area of the screen as long as my Publisher object has news. When there is no news, that area of the screen is hidden (or simply not rendered), and updating stops. I've used Ryan Bates's excellent Polling for Changes RailsCast as a starting point, but I'm stuck on a couple of points.

My intention is that if the Publisher object has news, its show() method renders a page with a <div id='news'></div> on it. Javascript will notice that div and replace it (and its contents) with any news that the Publisher has, and retrigger 5 seconds later. When the Publisher has no more news, Javascript will replace the <div id='news'></div> with an empty string. At the next trigger, there will be no more <div id='news'></div>, so the retrigger process will stop. At least, that's the intention.

First, the problems:

  1. Though I know my partial is getting called, it doesn't generate a visible change on the screen
  2. (Perhaps related to 1.) The javascript fn keeps getting called even there is no more news to display.

Briefly, here are the salient parts:

file: public/javascripts/application.js

$(function () {  
  if ($('#news').length > 0) {  
    setTimeout(updateNews, 5000);
  }
});  

function updateNews() {  
    $.getScript('/publisher/update_news.js');  
    setTimeout(updateNews, 5000);
}

file: config/routes.rb

resource :publisher, :only => [:show] do
  member {
    get :update_news
  }
end

file: app/controllers/publishers_controller.rb

def show
end

def update_news
  @publisher = find_publisher
  unless (@publisher.has_news?)
    return head :ok
  end
  # otherwise should render views/publisher/update_news.js.html
end

file: app/views/publisher/show.html.erb

<%= render :partial => 'publishers/show_news', 
           :locals => {:publisher => @publisher} %>

file: app/views/publisher/update_news.js.erb

<% t = escape_javascript(raw(render(:partial => 'publishers/show_news', 
                                    :locals => {:publisher => @publisher}))) %>
$('#news').replace_with(' + <%= t %> + ');

file: app/views/publisher/_show_news.html.erb

<div id='news'>
  <h4>latest news</h4>
  <%= simple_format publisher.news %>
</div>

Rails.logger.debug messages tell me that the _show_news.html.erb partial is getting called, both via the show() method and via the javascript-initiated updateNews() method. But I don't see the changes on the screen and (perhaps related) the updateNews function continues to get called after Publisher.has_news? returns false. (The latter problem would be explained if the jQuery replace_with() function always starts with the originally rendered page, not the results of its own modifications.)

So the two question: 1. Why don't I see visible changes to the screen? Am I mis-using jQUery's replace-with? 2. I'm suspicious of my technique for stopping the updates. What's the right way?

fearless_fool
  • 33,645
  • 23
  • 135
  • 217
  • BTW, there are numerous errors in my own code above, including the fact that once updateNews gets called, it will always re-trigger itself: there is no way to stop it (except for leaving the page). See my comment below to @Larry K to see what I ended up doing. – fearless_fool Aug 31 '11 at 14:25

1 Answers1

1

To help with the debugging:

Use fiddler (windows) or a Mac tool to see exactly what is being passed between your html/jScript page on your browser and the server.

Have you tried using the browser debugger to understand what is happening?

My guess is that the js being sent from your .js.erb page is not working well.

Community
  • 1
  • 1
Larry K
  • 47,808
  • 15
  • 87
  • 140
  • THWACK! (Sound of me slapping forehead...) I actually own a copy of Charles (http://www.charlesproxy.com/), which I use frequently for other things -- I don't know why I hadn't applied it to this debugging question. So yes, it helped me out a lot, as did the Web Console in Firefox. Ultimately, I restructured my code, dropping the setTimeout call in application.js and adding a `<%= javascript_tag("setTimeout(updateNews, 5000)") %> in my _show_news.html.erb template iff there is pending news. Works fine now. – fearless_fool Aug 30 '11 at 05:05