How are virtual attributes managed in memory?

1.2k views Asked by At

I'm going through Michael Hartl's rails tutorial and have come to a point where he defines a virtual attribute, remember_token and later assigns a value to it in a remember instance method:

class User < ApplicationRecord
  attr_accessor :remember_token
  ...

  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end
end

He then accesses the value of the virtual attribute in a helper method after remember is called:

def remember(user)
  user.remember
  cookies.permanent.signed[:user_id] = user.id
  cookies.permanent[:remember_token] = user.remember_token
end

My interpretation was that after the remember method is executed (and where remember_token is assigned it's removed from memory. Obviously this isn't the case here because it's still available to use when assigning a new value to cookies.permanent[:remember_token].

I guess my source of confusion stems from data persistence. Assuming that the remember_token is made into an instance variable with the help of attr_accessor, when does it officially become unavailable?

1

There are 1 answers

3
max On BEST ANSWER

Your assumption is wrong.

"Virtual attributes" is really just a term used for plain old instance attributes in models to differentiate from the database backed attributes that are persisted.

Instance attributes retain their value as long as the object which encapsulates them exists (or you explicitly nil the value). The object exists until the garbage collector can determine that it is no longer referenced.

class Person
  attr_accessor :name

  def initialize(name: nil)
    @name = name
    # or using the accessor
    self.name = name
  end
end

So if we create an instance of Person it will of course retain the value of name:

jane = Person.new(name: 'Jane')
jane.name # => 'Jane'

What you might be confusing is local variables which are only available in the block where they are defined:

class Person
  attr_accessor :name

  def say_hello
    # this local variable is garbage collect after the method is called
    phrase =  "Hello, my name is "
    puts phrase + name # we can omit self since it is implied
  end
end