views:

456

answers:

4

I have the following code:

   def show
    @game = $site.new_game_of_type(params[:id])
    @game.start
  end

  def update_game_time
    render :partial => 'countdown', :layout => false
  end

and the countdown partial:

<div id=countdown> <%= @game.running_time %></div>

In show.html.erb I have:

Time: <div id="countdown"> </div>

<%= periodically_call_remote(:frequency => 0.5, 
   :update => 'countdown', :url => {:action => :update_game_time}) %>

I want to create a game in the page that is showed by show, so I will have lot of ajax moving there but the user will not click anywhere. All the actions of the controller would be called from Javascript.

I got an error of @game being nil. It is nil even in the method update_game_time how can I make the @game variable to remain valid while the user is in that page?

+1  A: 

You need to pass the variable into the partial in order for it to be visible there.

def update_game_time
 render :partial => 'countdown', :layout => false, :locals => { :game => @game }
end

and then access it in the partial like so:

<div id=countdown> <%= game.running_time %></div>
workmad3
even if I do something like raise @game.running_time.to_s inside update_game_time I get a message saying that I ran:nil.running_time.to_s.....
Jordi
BTW, at least the local to partial seems to work (I have tried in an unrelated controller). Thanks for the tip.
Jordi
+2  A: 

Making a request to the server every 0.5 seconds is not such a good idea.
My suggestion is to load the running_time once and then use javascript to increase/decrease it.

Maybe you could do something like:

<div id=countdown><%= @game.running_time %></div>

in the view and then use some javascript on it, to update the timer:

window.onload = function() {
  var countdownDiv = document.getElementById('countdown');

  var timerValue = parseInt(countdownDiv.innerHTML); // assuming that your running_time is an int (seconds)

  var dateObj = new Date();

  dateObj.setTime( timerValue*1000 );
  countdownDiv.innerHTML = dateObj.getMinutes() + ":" + dateObj.getSeconds();

  var timer = setInterval("dispalyTimer()", 1000);

  dispalyTimer = function() {
    dateObj.setTime( ( (dateObj.getTime()/1000) + 1 )*1000 );
    countdownDiv.innerHTML = dateObj.getMinutes() + ":" + dateObj.getSeconds();
  }
}

This is just a basic example, but you get the point. Anyway it's better than to make a request to the server every half of second, for a timer that can work very well on the client side too.

andi
Thanks for the answer.There is any way the server can initiate the conversation with the client without a previous client event?The 0.5 seconds update is my hack to call the server periodically and let him update its information to the client. That's the best of my knowledge
Jordi
Why should the server initiate the connection/conversation? I'm not sure I understand. On a *nix platform you *could* use cron jobs (http://en.wikipedia.org/wiki/Cron) to make requests from the server, but I don't know if this approach is such a good idea either. Could you be a bit more specific on what you are trying to achieve?
andi
I have an underlying engine. and I want to use the web interface to let know the user what's going on and interact with the process. The user start a new game and then the engine will read the game definition and create the user interface. The game has time limits, have new incoming data, etc. Events I want to send to the user. This is possible, but my polling approach surely is not the most efficient
Jordi
I have updated my answer. Maybe it helps.
andi
After fighting with several solutions I decided to go for something like this. I have not tested it yet but I will use this code as base, thank you very much.
Jordi
+2  A: 

You should move the two lines from the show method to update_game_time, before the rendering. Otherwise @game is undefined, other than when rendering the show action.

bjorne
Upvoted this as it made me remember the rule for rails controllers:Each request to the server == a new instance of the controller. Therefore the ajax call to get the partial will be a new instance (without show having been called) and will therefore not have an @game variable to do anything with.
workmad3
+3  A: 

If you want the @game object to persist between requests, you need to store it somewhere. There are many ways to do this (for example, you could make it an ActiveRecord object and persist it in a database) but it looks to me like you want to use the session. A nice overview of the major issues involved in using sessions in Rails can be found at http://www.quarkruby.com/2007/10/21/sessions-and-cookies-in-ruby-on-rails but the basic usage is:

def show
  @game = $site.new_game_of_type(params[:id])
  @game.start
  session[:game] = @game
end

def update_game_time
  @game = session[:game]
  render :partial => 'countdown', :layout => false
end
Sam