Ricardo Huamani

Module 2 Evaluation - Cómo definir nuestro modelo Book con LazyRecord

May 08, 2020

Advertencia: Pude haberme comido alguna letra o coma.

Un modelo representa una entidad de tus datos almacenados. En nuestro caso queremos almacenar los libros que el usuario agrega con LazyRecord. Entonces creamos un modelo llamado Book (models/book.rb).

# models/book.rb
require "lazyrecord"

class Book < LazyRecord
  # Código
end

De acuerdo a las historias de usuario, cada Book que el usuario guarde, debe tener un estatus (status) y notas del usuario (notes). Estas deben poder leerse y modificarse luego (attr_accessor).

require "lazyrecord"

class Book < LazyRecord
  attr_accessor :status, :notes
  # Cuando el usuario guarde (cree) el Book, asumimos que no tiene notas
  # O sea, que es un string vacío
  def initialize(status:, notes: "")
    @status = status
    @notes = notes
  end
end

Pero también debemos guardar el día o fecha en el que se guardó el Book (guardó -> creó -> instanció).

require "lazyrecord"

class Book < LazyRecord
  attr_accessor :status, :notes

  def initialize(status:, notes: "")
    @status = status
    @notes = notes
    @date = Time.now
  end
end

Por otra parte, necesitamos una forma de llamar los datos de la API de Google y mostrarla en las vistas, pero llamar a la API cada vez que se genera una vista es muy tedioso. Así que mejor almacenamos la info de los libros en nuestro modelo. Y de paso sobrescribimos el ID por defecto de LazyRecord con el ID del libro en la API. Con esto podremos buscar (find) el libro usando el mismo ID de la API.

require "lazyrecord"
require "http"

class Book < LazyRecord
  attr_reader :id, :date, :external_data
  attr_accessor :status, :notes
  # Al momento de instanciarlo sobreescribimos el ID de LazyRecord
  # Con el ID de la API de Google. El cómo obtenemos el ID
  # del libro en la API depende de la aplicación
  def initialize(id:, status:, notes: "")
    @id = id # ID del libro que debe coincidir con la API de Google
    @status = status
    @notes = notes
    @date = Time.now
    @external_data = HTTP.headers(:accept => "application/json").get(ENDPOINT_CON_ID).parse
  end
end

De esta forma la variable de instancia @external_data contiene toda la info del libro de la API de Google y lo llamamos solo cuando se instancia el libro. Para instanciarlo podemos:

id = algun_codigo_para_obtener_el_ID_del_libro
book = Book.new(id: id, status: "want to read")

El @notes por defecto está vacío, el @date es automático y el @external_data se llama por defecto con el ID que provees que debe coincidir con algun ID de los libros de la API. Con esto ya tenemos un Modelo Book que podemos instanciar y en donde podemos guardar toda la data que necesitamos.

Pero podemos mejorarlo aún mas, vamos a crearle algunos métodos de ayuda. Supongamos que tenemos el libro instanciado y queremos obtener su título, la URL de su portada, sus autores o su descripción. Podríamos extraerlo directamente de @external_data, pero sería un poco tedioso, así que crearemos algunos métodos para obtenerlos.

class Book < LazyRecord
  attr_reader :id, :date
  attr_accessor :status, :notes

  def initialize(id:, status:, notes: "")
    @id = id
    @status = status
    @notes = notes
    @date = Time.now
    @external_data = HTTP.headers(:accept => "application/json").get(ENDPOINT_CON_ID).parse
  end

  def img_url
    @external_book['volumeInfo']['imageLinks']['thumbnail']
  end

  def title
    @external_book['volumeInfo']['title']
  end

  # Curiosidad: authors devuelve un array de strings. Así que
  # para mostrarlos podemos usar el método join en las vistas
  def authors
    @external_book['volumeInfo']['authors']
  end

  def description
    @external_book['volumeInfo']['description']
  end
end

Hasta aquí ya tenemos nuestro modelo Book, pero también necesitamos algunos libros ya almacenados en nuestra app para probar que funciona y poder mostrarlos en la vista My Books. Entonces creamos un pequeño script independiente que rellene esos libros es nuestra data. Y lo haremos desde nuestra carpeta raíz.

# book_seeder.rb
require_relative "models/book"

books = [
  Book.create(id: '5W6cnfQegYcC', status: 'read'),
  Book.create(id: 'ntA5AlD3p4AC', status: 'read'),
  Book.create(id: 'BvqcDwAAQBAJ', status: 'read'),
  Book.create(id: 'JFdMAQAAIAAJ', status: 'read'),
]

Hemos usado IDs de libros que encontramos por ahí jugando con la API de Google. Con esto ya creamos y almacenamos nuestros libros y ademas los asignamos al array books. Pero para estar seguros, vamos a mostrar algunos de sus datos con p o puts.

# book_seeder.rb
require_relative "models/book"

books = [
  Book.create(id: '5W6cnfQegYcC', status: 'read'),
  Book.create(id: 'ntA5AlD3p4AC', status: 'read'),
  Book.create(id: 'BvqcDwAAQBAJ', status: 'read'),
  Book.create(id: 'JFdMAQAAIAAJ', status: 'read'),
]

books.each_with_index do |book, i|
  puts "BOOK #{i + 1}"
  puts "Title:"
  p book.title
  puts "Image:"
  p book.img_url
  puts "Authors:"
  p book.authors
  puts "Description:"
  p book.description
  puts "----------"
end
$ bundle exec ruby book_seeder.rb

Con esto hemos comprobado que efectivamente se crearon los libros y se almacenaron en nuestro archivo lazyrecord.pstore y podemos usarlos en nuestra aplicación.


Written by Ricardo Huamani Parian. Full-stack web developer, autodidact, and technical writer. I enjoy coding and sharing about technology. You can follow me on Twitter