# Ajax, Observers e autorefresh

**URL:** <https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908>\
**Category:** IT\
**Created:** [March 10, 2010, 10:51am UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908 "2010-03-10T10:51:09Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 10, 2010, 10:51am UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/1 "2010-03-10T10:51:09Z")

</div>

Ciao a tutti, mi servirebbe una dritta su come implementare  
l’autorefresh di una lista di posts.

L’idea e’, che se un utente sta guardando una pagina che lista i suoi  
post e quelli del suo gruppo, dovrebbe vedere arrivare i nuovi post  
eseguiti dagli altri in tempo reale, cioe dinamicamente senza fare il  
reload della pagina.

Non ho molta dimestichezza con Ajax, ma dovrebbe avere a che fare con i  
metodi di ActionView::Helpers::PrototypeHelper:

```
* build_callbacks
* build_observer
* button_to_remote
* evaluate_remote_response
* form_remote_for
* form_remote_tag
* link_to_remote
* method_option_to_s
* observe_field
* observe_form
* options_for_ajax
* periodically_call_remote
* remote_form_for
* remote_function
* submit_to_remote
* update_page
* update_page_tag

```

la pagina che devo refreshare e’ l’index dell’home controller:

* * *

## root@webby2066:/var/rails/flitter# cat ./app/views/home/index.html.erb … \<%= render :partial =\> “flits\_list”, :locals =\> { :flits =\> @flits }%\>

che sostanzialmente chiama un parziale che implementa ogni singolo post:

* * *

root@webby2066:/var/rails/flitter# cat  
./app/views/home/\_flits\_list.html.erb

 \<% flits.each do |flit| %\> class="first"\<% end %\>\> \<%= image\_tag flit.user.gravatar\_url %\> 
 \<%= link\_to flit.user.username, user\_flits\_path(flit.user.username) %\> \<%= h flit.message %\> 
 \<%= distance\_of\_time\_in\_words\_to\_now(flit.created\_at) %\> ago 

 \<% end %\>
--------------------------------------------------------------

in un controller diverso da home, ho un “evento trigger” che e’  
flit.save! e dovrebbe scatenare il refresh di home/index.html.erb

Non mi e’ del tutto chiaro pero’ se c’e’ un metodo tra quelli elencati  
prima, idoneo a rilevare l’evento trigger flit.save! che in sostanza  
salva un nuovo post nel DB.

Ringrazio in anticipo per ogni suggerimento  
Ciao Luca

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 10, 2010, 11:17am UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/2 "2010-03-10T11:17:07Z")

</div>

Il 10 marzo 2010 10.51, Luca G. Soave [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) ha scritto:

> metodi di ActionView::Helpers::PrototypeHelper:
> 
> - observe\_form
> - options\_for\_ajax
> - periodically\_call\_remote
> - remote\_form\_for
> - remote\_function
> - submit\_to\_remote
> - update\_page
> - update\_page\_tag

Ciao,

premetto che, dopo un periodo iniziale irto di difficoltà, ho  
abbandonato del tutto rjs e i PrototypeHelper (e veramente anche  
Prototype, perché scoprire jQuery è stato un po’ come quando cerchi di  
lavorare a tentoni nel buio e a un certo punto accendono la luce).

Quello che ti serve è periodically\_call\_remote; la cosa più pulita è  
avere un metodo di un qualche controller che ti restituisca un json  
contenente una variabile boolean che ti dica se è necessario il  
refresh oppure no, in modo che la risposta sia sempre rapidissima.

Poi, quando ti serve fare il refresh, potresti fare una nuova chiamata  
all’index di home (ad esempio con remote\_function), da cui farti  
restituire solo il partial da rimpiazzare (la funzione potrebbe anche  
usare rjs, volendo…).

La questione è se vuoi fare tutto con gli helper di rails o se vuoi  
fare tutto con javascript.

pietro

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 10, 2010, 1:01pm UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/3 "2010-03-10T13:01:54Z")

</div>

puoi anche farti spedire direttamente i nuovi post in html e aggiungerli  
alla lista oppure ricaricare semplicemente la lista:

new Ajax.PeriodicalUpdater(‘items’, ‘/items’, {  
method: ‘get’, frequency: 3, decay: 2  
});

> Poi, quando ti serve fare il refresh, potresti fare una nuova chiamata  
> all’index di home (ad esempio con remote\_function), da cui farti  
> restituire solo il partial da rimpiazzare (la funzione potrebbe anche  
> usare rjs, volendo…).

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 10, 2010, 1:28pm UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/4 "2010-03-10T13:28:14Z")

</div>

Il 10 marzo 2010 13.01, Alessandro S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) ha  
scritto:

> puoi anche farti spedire direttamente i nuovi post in html e aggiungerli  
> alla lista oppure ricaricare semplicemente la lista:
> 
> new Ajax.PeriodicalUpdater(‘items’, ‘/items’, {  
> method: ‘get’, frequency: 3, decay: 2  
> });

Sì, è anche questa una soluzione ma, avendola provata in passato, non  
fa un bell’effetto, specie se la lista non è leggerissima.

Magari prova, in effetti così è molto semplice, ma se vedi che lo  
sfarfallìo è percettibile, riconsidera l’idea di modificare il dom  
solo quando serve.

pietro

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 10, 2010, 5:04pm UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/5 "2010-03-10T17:04:40Z")

</div>

Grazie a Pietro e Alessandro x le info.

Mi pare di capire che sia periodically\_call\_remote che  
Ajax.PeriodicalUpdater siano metodi “attivi” di polling, per cosi’ dire.

Non esiste, che voi sappiate, un Observer di ActiveRecord in grado di  
mandare una callback per una data commit sul DB (.save)? Oppure una cosa  
tipo after\_create() di ActiveRecord::Callbacks che scatena un evento  
ajax?

Sto solo immaginando, perche’ non ho esperienza in questi metodi.

Il problema e’ che dentro il partial,  
./app/views/home/\_flits\_list.html.erb c’e diversa roba, tra qui una  
query al db \<%= h flit.message %\> che verrebbe eseguita nel mio caso  
ogni 2 secondi x tutto il periodo in cui il browser utente rimane aperto  
sulla pagina, moltiplicato x tutti gli utenti collegati nell’unita’ di  
tempo … poco scalabile credo.

Sto solo speculando, ma mi piacerebbe innescare un certo numero di  
soluzioni percorribili e di confronti.

Grazie a tutti  
Luca G.S.

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 10, 2010, 6:35pm UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/6 "2010-03-10T18:35:41Z")

</div>

Luca G. Soave wrote:

> Grazie a Pietro e Alessandro x le info.
> 
> Mi pare di capire che sia periodically\_call\_remote che  
> Ajax.PeriodicalUpdater siano metodi “attivi” di polling, per cosi’ dire.
> 
> Non esiste, che voi sappiate, un Observer di ActiveRecord in grado di  
> mandare una callback per una data commit sul DB (.save)? Oppure una cosa  
> tipo after\_create() di ActiveRecord::Callbacks che scatena un evento  
> ajax?

Direi che si tratta di polling, un aggiornamento sul server come puÃ²  
avere relazioni con i clients che interrogano il database? Impostando un  
intervallo di check moderato, non credo si appesantisca troppo il server

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 10, 2010, 6:04pm UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/7 "2010-03-10T18:04:31Z")

</div>

On 10/03/2010 17:04, Luca G. Soave wrote:

> 

in teoria, non ha molto senso mettere mettere una logica che implica  
AJAX dentro un modello, altrimenti non sarebbe un pattern MVC 😛

in caso puoi farlo nel controller: riprendendo l’esempio di after\_create  
di ActiveRecord, vorrà dire che nella action ‘create’ farai qualcosa  
dopo aver salvato il modello.

per quanto riguarda il partial, puoi usare una chiamata AJAX  
periodicamente, come ti hanno già consigliato. per quanto riguarda la  
scalabilità, di sicuro puoi usare il “fragment caching”. Dovrai  
impostare un observer sul modello per aggiornare il contenuto del  
partial _cachato_.

se poi la scalabilità è davvero un problema urgente, potresti valutare  
qualcosa tipo Redis (un db chiave/valore che fa anche molte altre cose:  
[Google Code Archive - Long-term storage for Google Code Project Hosting.](http://code.google.com/p/redis/)) + redis\_store (plugin Rails per fare il  
caching usando Redis: [GitHub - redis-store/redis-store: Namespaced Rack::Session, Rack::Cache, I18n and cache Redis stores for Ruby web frameworks](http://github.com/jodosha/redis-store)). Tra le  
altre cose, entrambe i progetti sono scritti da programmatori italiani  
🙂

ciao,  
A.

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 11, 2010, 12:39am UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/8 "2010-03-11T00:39:06Z")

</div>

Il 10 marzo 2010 17.04, Luca G. Soave [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) ha scritto:

> Grazie a Pietro e Alessandro x le info.
> 
> Mi pare di capire che sia periodically\_call\_remote che  
> Ajax.PeriodicalUpdater siano metodi “attivi” di polling, per cosi’ dire.
> 
> Non esiste, che voi sappiate, un Observer di ActiveRecord in grado di  
> mandare una callback per una data commit sul DB (.save)? Oppure una cosa  
> tipo after\_create() di ActiveRecord::Callbacks che scatena un evento  
> ajax?

Come ti hanno già detto, no, non si può. Alcune applicazioni web  
implementano eventi push tenendo aperto un socket (java o flash) ma, a  
parte il fatto di avere una dipendenza in più, non credere che, per il  
server, mantenere (potenzialmente) migliaia di connessioni aperte sia  
un carico trascurabile.  
Altre applicazioni simulano un evento push “trattenendo” le risposte a  
eventi poll, ma è una cosa ancora più complicata e pesante per il  
server.

La cosa più semplice e leggera è appunto quella suggeritati (vedi sotto).

> Sto solo immaginando, perche’ non ho esperienza in questi metodi.
> 
> Il problema e’ che dentro il partial,  
> ./app/views/home/\_flits\_list.html.erb c’e diversa roba, tra qui una  
> query al db \<%= h flit.message %\> che verrebbe eseguita nel mio caso  
> ogni 2 secondi x tutto il periodo in cui il browser utente rimane aperto  
> sulla pagina, moltiplicato x tutti gli utenti collegati nell’unita’ di  
> tempo … poco scalabile credo.

Ecco, qui c’è un problema grossissimo, indipendentemente da ajax e  
quant’altro: le view _non devono_ fare query. Le view devono solo  
mostrare, nient’altro.

Poi, c’è un altro problema, e cioè che il partial è complesso. E anche  
stavolta, questo è un problema indipendentemente da ajax.  
Semplicemente, scomponi il partial in pezzi più piccoli, e uno di  
questi pezzi si limiterà a mostrare la lista.

> una query che verrebbe eseguita nel mio caso ogni 2 secondi

Due secondi mi sembra un’esagerazione, in genere cinque (o anche  
dieci) secondi vanno più che bene; sei proprio sicuro che sia  
indispensabile? Molte applicazioni mostrano una buona reattività pur  
tenendosi appunto intorno ai dieci secondi e oltre.

Se ripetere tante volte la stessa query è davvero un problema, ci sono  
tecnologie ad hoc per la persistenza dello stato (che in questo caso è  
nuovi post sì / nuovi post no), come ti ha suggerito Andrea, che però  
ha senso indagare solo se è vera almeno una delle due ipotesi:

a) hai già centinaia di utenti prenotati che terranno aperto il  
browser sulla tua applicazione (ma questo probabilmente significa che  
hai bisogno di una certa infrastruttura, ad esempio una banda “seria”  
e un server come si deve);

b) hai voglia di imparare a usare redis 🙂

Tra l’altro, come dicevo nell’email precedente, usare una chiamata  
ajax che ridisegni migliaia di volte la stessa identica lista è uno  
spreco enorme, ed è un carico sia per il server (che finché non  
finisce di trasmettere una risposta resta impegnato, ed ha così minore  
capacità di risposta per gli altri) che per il client, e l’utente si  
ritroverebbe un computer inchiodato da un browser che ridisegna lo  
stesso pezzo di pagina; anche l’effetto visivo non è il massimo,  
perché lo sfarfallìo si vede.

Ma questo non è necessario: quando mostri la pagina passi al  
javascript l’ora corrente (lato server), così il javascript può  
interrogare il server chiedendo: è cambiato niente dall’ora X? Se la  
risposta è no, non fai niente; se è sì, si ridisegna la pagina.

pietro

---

<div class="post-metadata">

**Author:** ![jeanluca](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/74df32/32.png) [@jeanluca](https://www.ruby-forum.com/u/jeanluca)\
**Post date:** [March 11, 2010, 11:01am UTC](https://www.ruby-forum.com/t/ajax-observers-e-autorefresh/184908/9 "2010-03-11T11:01:15Z")

</div>

Ok Pietro, grazie per i numerosi consigli e le opzioni che mi hai  
prospettato. Mi sembra di avere un quadro un po piu’ completo sullo  
“stato dell’arte”.

Provo a distillare il mio compromesso sugli elementi forniti.

Ciao  
Luca
