def reify_from_row(row)
      #the tap method allows preconfigured methods and values to
      #be associated with the instance during instantiation while also automatically returning
      #the object after its creation is concluded.
      self.new.tap do |card|
        self.attributes.keys.each.with_index do |key, index|
          #sending the new instance the key name as a setter with the value located at the 'row' index
          card.send("#{key}=", row[index])
          #string interpolation is used as the method doesn't know the key name yet
          #but an = sign is implemented into the string in order to asssociate it as a setter
        end
      end
    end
def reify_from_row(row)
      #the tap method allows preconfigured methods and values to
      #be associated with the instance during instantiation while also automatically returning
      #the object after its creation is concluded.
      self.new.tap do |card|
        self.attributes.keys.each.with_index do |key, index|
          #sending the new instance the key name as a setter with the value located at the 'row' index
          card.send("#{key}=", row[index])
          #string interpolation is used as the method doesn't know the key name yet
          #but an = sign is implemented into the string in order to asssociate it as a setter
        end
      end
    end
opposite of abstraction is reification i.e. I'm getting the raw data of these variables