# Variabili d'istanza non visibili

**URL:** <https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341>\
**Category:** IT\
**Created:** [August 25, 2009, 10:18am UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341 "2009-08-25T10:18:46Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 25, 2009, 10:18am UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/1 "2009-08-25T10:18:46Z")

</div>

Ciao a tutti, vorrei fare un po’ di chiarezza sulle variabili d’istanza  
in ruby/rails: ho notato un comportamento diverso di queste variabili  
usando un modello in rails, ed una classe in ruby (provata con irb).

Con entrambe: ho notato che creando una variabile d’istanza non nel  
costruttore essa non Ã¨ visibile negli altri metodi, viene ignorata  
(facendo ad esempio @var = “valore”). PerchÃ¨? Il bello Ã¨ dichiararle con  
@, se non si possono dichiarare nei metodi avrebbero fatto meglio a  
farle dichiarare a livello di classe.

Con una classe in ruby: se dichiaro la variabile d’istanza nel  
costruttore essa Ã¨ visibile e modificabile negli altri metodi

Con un modello: dichiarandole nel costruttore alcune sono visibili,  
alcune no

def initialize(session)  
@session = session  
@user = nil  
end

def log\_in(user)  
if user  
@user = user  
…  
end  
end

In questo caso @session viene letta e modificata negli altri metodi,  
mentre @user no.  
O meglio, in log\_in, @user viene impostata correttamente (facendo puts  
vedo che Ã¨ impostata a user), ma Ã¨ come se non fosse d’istanza, perchÃ¨  
usando @user in altri metodi questo vale ancora nil. Fatemi sapere,  
spero che la domanda sia interessante e non una cosa banale. ciao

nicola

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 25, 2009, 10:31am UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/2 "2009-08-25T10:31:52Z")

</div>

Le variabili d’istanza sono accessibili ovunque all’interno  
dell’applicazione indipendentemente dal fatto che siano state o meno  
dichiarate nell’initializer.

Il tuo codice infatti funziona. Prova ad eseguire questo

class LoginMock

def initialize(session)  
@session = session  
@user = nil  
end

def log\_in(user)  
if user  
@user = user  
end  
end

def give\_me\_the\_user  
@user  
end

end

c = LoginMock.new(“I am a session”)  
c.log\_in(“weppos”)  
puts c.give\_me\_the\_user

Il problema è senza dubbio altrove. Tieni in considerazione che se apri  
una  
pagina A (login) e B (verifica), anche se hai una variabile d’istanza in  
A  
non sarà visibile in B perché sono due esecuzioni differenti.  
Per trasportarti il valore devi ricorrere all’uso di una sessione o di  
un  
cookie.

– Simone

2009/8/25 Nicola N. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> end  
> end

–  
Simone C.

Site & Blog: [http://www.simonecarletti.com](http://www.simonecarletti.com)  
Email: removed\_email\_address@domain.invalid  
LinkedIn: [http://linkedin.com/in/weppos](http://linkedin.com/in/weppos)  
Nick: weppos | Skype: weppos

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 25, 2009, 10:33am UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/3 "2009-08-25T10:33:37Z")

</div>

Il giorno 25 agosto 2009 10.18, Nicola N.[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) ha  
scritto:  
scusa, non ho capito.

> Con entrambe: ho notato che creando una variabile d’istanza non nel  
> costruttore essa non è visibile negli altri metodi, viene ignorata

class SenzaCostruttore  
def settala  
@miavar = 3  
end

def dimmela  
@miavar  
end  
end

> > a = SenzaCostruttore.new  
> > #SenzaCostruttore:0x4043b6c  
> > a.dimmela  
> > nil  
> > a.settala  
> > 3  
> > a.dimmela  
> > 3  
> > a  
> > #\<SenzaCostruttore:0x4011180 @miavar=3\>

class ColCostruttore  
def initialize  
@questa = 4  
end

def settala  
@miavar = 3  
end

def dimmela  
puts @questa  
@miavar  
end  
end

> > a = ColCostruttore.new  
> > #\<ColCostruttore:0x4023164 @questa=4\>  
> > a.dimmela  
> > nil  
> > a.settala  
> > 3  
> > a.dimmela  
> > 3  
> > a  
> > #\<ColCostruttore:0x4023164 @miavar=3, @questa=4\>

non è che, in rails, stai tentando di accedere a una variabile  
d’istanza di un model da dentro un controller, o altro?

pietro

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 25, 2009, 11:24am UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/4 "2009-08-25T11:24:53Z")

</div>

per pietro:

Ok, ho fatto un’altra prova e ho visto che le variabili posso  
dichiararle anche in altri metodi, e sono comunque visibili… ChissÃ  
come avevo provato prima

per simone:

forse ho intuito dove sta il problema. l’istanza della classe viene  
creata nell’Application, in questo modo

before\_filter :initialize\_session  
def initialize\_session  
@user\_session ||= UserSession.new(session)  
end

before\_filter :fetch\_logged\_in\_user  
def fetch\_logged\_in\_user  
if @user\_session  
@current\_user = @user\_session.get\_logged\_user  
end

```
return nil

```

end

La classe che deve contenere la variabile Ã¨ UserSession  
Poi uso @user\_session dove voglio (in teoria), per impostare la  
sessione. Forse il problema Ã¨ dato dal before\_filter. Io vorrei che  
venisse creata un’istanza di UserSession una tantum per gestire le  
sessioni dell’utente corrente.

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 25, 2009, 11:37am UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/5 "2009-08-25T11:37:26Z")

</div>

Un filtro in before\_filter lavora nel contesto dell’istanza. Quindi ogni  
filtro ha visibilità delle istanze create dai filtri precedenti ed ogni  
azione ha visibilità delle istanze create da un qualsiasi filtro.

class MyController

before\_filter :load\_user

def action  
# qui @user == :me  
end

protected

```
def load_user
  @user = :me
end

```

end

I tuoi due filtri, dunque, sembrano corretti, fermo restando che non mi  
quadra quel return nil al fine del secondo filtro.  
Controlla solo che i filtri vengano eseguiti nell’ordine che ti aspetti,  
altrimenti le variabili non le avrai a disposizione. Invece che un  
filtro,  
potresti usare un metodo e sfruttare il lazy loading per avere la  
variabile  
a disposizione esattamente dove e quando ti serve.

class ApplicationController

protected

```
def current_session
  @user_session ||= UserSession.new(session)
end

def current_user
  # evita if quando non servono e soprattutto
  # evita di usare if come "patch" per nil exception
  # può un UserSession.new mai tornare nil?
  # e se lo torna, è veramente corretto?
  @current_user = current_session.get_logged_user
end

```

end

class MyController \< ApplicationController

def alpha  
# qui non chiamo mai user session quindi risparmio risorse e filtri  
end

def beta  
@stuff = current\_user.do\_stuff  
end

end

Se infatti guardi il funzionamento di Authlogic, a scopo didattico,  
vedrai  
che funziona esattamente in questo modo.  
Hai un metodo, che può essere usato anche come before\_filter, che imposta  
una variabile current\_user che puoi richiamare nell’azione o nel  
template  
corrente.

– Simone

2009/8/25 Nicola N. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> before\_filter :initialize\_session  
> return nil  
> Ml mailing list  
> removed\_email\_address@domain.invalid  
> [http://lists.ruby-it.org/mailman/listinfo/ml](http://lists.ruby-it.org/mailman/listinfo/ml)

–  
Simone C.

Site & Blog: [http://www.simonecarletti.com](http://www.simonecarletti.com)  
Email: removed\_email\_address@domain.invalid  
LinkedIn: [http://linkedin.com/in/weppos](http://linkedin.com/in/weppos)  
Nick: weppos | Skype: weppos

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 26, 2009, 3:28pm UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/6 "2009-08-26T15:28:02Z")

</div>

Ciao Nicola,

non sono proprio sicuro cosa vuoi fare, comunque ho qualche chiarimenti:

- Per i modelli Rails, #initialize non vienne chiamato quando  
l’oggetto è creato dalla db, quindi la variabile vienne mai  
innizzialisato
- Sovrascrivere #initialize per sottoclasse non è molto  
consigliato. In quel caso, chiama almeno #super
- Per i controller: I variabili assegnato nel :before\_filter sono  
visibile sia nel controller, sia nel view - ma _solo_ per la richiesta  
attuale  
Non saranno li per la prossima richiesta - ricordi che HTTP è un  
protocollo stateless. Questo vale per _tutti_ i variabili della  
runtime! (O almeno si assume sempre che la runtime è “vuota” al inizio  
della richiesta)
- Dati per la sessione si può mettere nel hash “session”. I  
contenuti di quel hash sono sempre disponibile in tutte le richieste  
della stessa sessione. Non è consigliato mettere dei oggi complessi  
nella session-hash
- Dati nella db sono (ovviamente) sempre disponibile ovunque

Ciao,  
Daniel

Il giorno 25/ago/09, alle ore 11:24, Nicola N. ha scritto:

> before\_filter :initialize\_session  
> return nil  
> Ml mailing list  
> removed\_email\_address@domain.invalid  
> [http://lists.ruby-it.org/mailman/listinfo/ml](http://lists.ruby-it.org/mailman/listinfo/ml)

–  
Daniel H.  
Software Architect  
removed\_email\_address@domain.invalid

Net7  
Via Marche 8a - 56123 Pisa

> **[home - Net7](https://www.netseven.it/)**
>
> CreateDevelopAmplifyDesign, software ecomunicazione un unicoprocesso.Create/ Il Design Attraverso la conoscenza, la relazione, il confronto, individuiamo

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 30, 2009, 3:41pm UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/7 "2009-08-30T15:41:44Z")

</div>

vi rinrgazio per le risposte numerose e gli spunti, ho provato a capire  
cosa non funzionava senza successo.

- Ho provato a mettere una variabile di classe in UserSession e a fare  
cosÃ¬ per vedere che istanza venisse chiamata:

- ho provato salvando una copia di user con  
Marshal.load(Marshal.dump(user)), pensando che rimanesse un puntatore a  
quando viene letta nel database e quando venisse cancellata il puntatore  
puntasse a nil

Non so se sia un problema della mancanza di stato HTTP, perchÃ¨ l’istanza  
di UserSession che uso Ã¨ sempre la stessa (credo, perchÃ¨ non ho ben  
chiaro come vengano servite le richieste dal server ai client) quindi  
chiamandone un metodo dovrei impostarne una variabile.

Visto tutto questo, preferisco rinunciare a salvare l’utente quando  
faccio il login, e leggo dal database i dati che mi servono. poi con  
calma mi metterÃ² ad analizzare tutto quanto, per ora resta cosÃ¬.

per daniel:

non ho capito perchÃ¨ Ã¨ meglio che non scriva il costruttore: non c’Ã¨  
nessuna sopraclasse esplicita, quindi secondo me puÃ² andare cosÃ¬. mi  
sbaglio?

Saluti a tutti e grazie,

nicola

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [August 31, 2009, 1:14pm UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/8 "2009-08-31T13:14:16Z")

</div>

Ciao,

Il giorno 30/ago/09, alle ore 15:41, Nicola N. ha scritto:

> quando chiamo i vari metodi dell’istanza @user\_session il numero  
> dell’istanza è sempre lo stesso, ma le variabili che non vengono  
> impostate nel costruttore non ci sono

Non so cosa vuoi dire con ‘le variabili che non vengono impostate nel  
costruttore non ci sono’. Per cosa riguarda ruby, una variabile di una  
istanza nasce quando è assegnato un valore. Ci saranno fine al cleanup  
dell’oggetto. Non importa se sono impostati nell costruttore o in  
qualsiasi altro metodo dell’oggetto. Attenti: Se chiami un metodo  
della class (tipo

def self.mett  
@var = ‘val’  
end

la variabile sarà una variabile dell’istanza dell’oggetto della classe  
(tutto chiaro? 😉

> Non so se sia un problema della mancanza di stato HTTP, perchè  
> l’istanza  
> di UserSession che uso è sempre la stessa (credo, perchè non ho ben  
> chiaro come vengano servite le richieste dal server ai client) quindi  
> chiamandone un metodo dovrei impostarne una variabile.

Non puoi essere sicuro se l’istanza sia sempre la stessa. È possibile  
ritenere un oggetto dentro la runtime, anche tra richiesti. MA quando  
una applicazione Rails vienne messo in produzione ci saranno più di  
una istanza della runtime! Non ci sara nessun modo di scoprire se  
esistono altri runtime o quale oggetti hanno. Quindi l’unico modo di  
ritenere dati tra richiesti è usare la db o “session”.

> per daniel:
> 
> non ho capito perchè è meglio che non scriva il costruttore: non c’è  
> nessuna sopraclasse esplicita, quindi secondo me può andare così. mi  
> sbaglio?

Ho capito che la tua classes UserSession e una sottoclasse di  
ActiveRecord::Base? In quel caso, #initialize funziona come prevista  
se chiami

UserSession.new

ma, se chiami qualche metodo come

UserSession.find(…)

Rails crea l’oggetto senza usare #new, quindi non vienne chiamato  
neanche #initialize.

Per tutti i “record” (sottoclassi di ActiveRecord::Base) è sempre  
meglio usare i callback.

Ciao,  
Daniel

> [http://lists.ruby-it.org/mailman/listinfo/ml](http://lists.ruby-it.org/mailman/listinfo/ml)  
> –  
> Daniel H.  
> Software Architect  
> removed\_email\_address@domain.invalid

Net7  
Via Marche 8a - 56123 Pisa

> **[home - Net7](https://www.netseven.it/)**
>
> CreateDevelopAmplifyDesign, software ecomunicazione un unicoprocesso.Create/ Il Design Attraverso la conoscenza, la relazione, il confronto, individuiamo

---

<div class="post-metadata">

**Author:** ![nicola55](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/5fc32e/32.png) [@nicola55](https://www.ruby-forum.com/u/nicola55)\
**Post date:** [September 4, 2009, 8:37pm UTC](https://www.ruby-forum.com/t/variabili-distanza-non-visibili/174341/9 "2009-09-04T20:37:16Z")

</div>

ciao daniel,

grazie per avermi risposto di nuovo. Allora, riguardo ai vari punti

1. la differenza tra variabili d’istanza e di classe mi Ã¨ chiara, e ho  
capito che in rails una variabile d’istanza puÃ² essere dichiarata in  
qualsiasi metodo e da quel momento in poi ci sarÃ .

2. la classe UserSession non Ã¨ sottoclasse di ActiveRecord: avevo  
bisogno di spostare la logica delle sessioni ad un livello piÃ¹ alto per  
poterle usare da dovunque. Se stava soltanto nel controller delle  
sessioni non potevo creare una sessione da un altro controller.  
Ho creato quindi un modello che non ha riferimenti nel database per  
gestire l’hash session.

3. grazie per la precisazione su come funziona new e find, vale anche  
per modelli non active record?

Con UserSession volevo proprio gestire l’hash session per non gestirlo  
altrove: mi sarebbe piaciuto salvare l’utente come variabile d’istanza  
quando lo passo a @userSession, ma non funziona. ho associato  
all’istanza un ID e quello corrispondeva, ma l’utente non veniva  
salvato.  
Infine ho rinunciato a procedere cosÃ¬, e dal modello interrogo il  
database con il dato in session[:user\_id]. Spero di essermi spiegato a  
sufficienza, grazie a tutti per la panoramica

nicola
