Skip to content

Sembrando una Base de Datos en Ruby on Rails

ALT

David Morales

Photo por Jeremy Bishop en Unsplash

Ruby on Rails tiene herramientas excelentes para sembrar una base de datos (rellenarla con datos), y gracias al trabajo de la comunidad, muchas gemas hacen esta tarea más fácil.

Aparte de sembrar una base de datos, tenemos herramientas útiles para comprobar la base de datos y organizar mejor las semillas de datos.

¿Quieres ver este artículo en formato video?

Creando una aplicación de ejemplo

Empecemos creando una aplicación nueva.

rails new ejemplo
cd ejemploCode language: Shell Session (shell)

Creando un modelo

Después, genera un modelo nuevo. Si tienes curiosidad, tecleando rails generate (o el atajo rails g), verás todos los generadores disponibles.

rails g model Pelicula titulo director sinopsis:text vista_en:dateCode language: Shell Session (shell)

Aquí estás definiendo titulo y director como cadenas (el tipo por defecto si no se especifica), sinopsis como texto, y vista_en como fecha (cuando se definen fechas, sin hora, la convención es añadir en al nombre).

Rails generará una migración adaptada a la base de datos por defecto, que es SQLite. Las migraciones se guardan en db/migrate. Veamos cómo es:

class CreatePeliculas < ActiveRecord::Migration[6.1]
  def change
    create_table :peliculas do |t|
      t.string :titulo
      t.string :director
      t.text :sinopsis
      t.date :vista_en

      t.timestamps
    end
  end
endCode language: Ruby (ruby)

Como puedes ver, Rails añade la versión que estás usando entre corchetes al final de la clase padre.

La directiva de timestamps generará los campos created_at y updated_at automáticamente. Muy útil.

Vamos a ejecutarlo.

$ rails db:migrate
== 20210311174407 CreatePeliculas: migrating =====================================
-- create_table(:peliculas)
   -> 0.0020s
== 20210311174407 CreatePeliculas: migrated (0.0021s) ============================Code language: Shell Session (shell)

Ahora Rails ha creado la tabla. Por si acaso te has equivocado en algo, siempre puedes volver atrás:

$ rails db:rollback
== 20210311174407 CreatePeliculas: reverting =====================================
-- drop_table(:peliculas)
   -> 0.0019s
== 20210311174407 CreatePeliculas: reverted (0.0064s) ============================Code language: Shell Session (shell)

Este comando acepta un parámetro step opcional para volver atrás tantas migraciones como necesites. Por ejemplo, si quieres deshacer 2 migraciones, puedes hacerlo así: rails db:rollback STEP=2

Vamos a ver cómo está el esquema en db/schema.rb después de ejecutar la migración:

ActiveRecord::Schema.define(version: 2021_03_11_174407) do

  create_table "peliculas", force: :cascade do |t|
    t.string "titulo"
    t.string "director"
    t.text "sinopsis"
    t.date "vista_en"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

endCode language: Ruby (ruby)

¡Bien! Este archivo contendrá el esquema entero de la base de datos a medida que vayamos haciendo migraciones.

Comandos de Rails

¿Cómo puedes saber los comandos de Rails que hay disponibles? Puedes ver una lista usando el parámetro -T:

rails -TCode language: Shell Session (shell)

Incluso puedes filtrar por espacio de nombre, como db:

rails -T dbCode language: Shell Session (shell)

Creando algunas semillas

Vamos a la parte interesante de este artículo. Abre el archivo db/seeds.rb, y pega esto:

Pelicula.destroy_all

Pelicula.create!([{
  titulo: "Soul",
  director: "Pete Docter",
  sinopsis: "Un músico que ha perdido su pasión por la música es transportado fuera de su cuerpo y debe encontrar el camino de regreso con la ayuda de un alma infantil que aprende sobre sí misma.",
  vista_en: 1.week.ago
},
{
  titulo: "El Señor de los Anillos: La Comunidad del Anillo",
  director: "Peter Jackson",
  sinopsis: "En la adormecida e idílica Comarca, un joven hobbit recibe un encargo: custodiar el Anillo Único y emprender el viaje para su destrucción en las Grietas del Destino.",
  vista_en: 2.years.ago
},
{
  titulo: "Terminator 2",
  director: "James Cameron",
  sinopsis: "Arnold Schwarzenegger es Terminator: un exterminador modelo T-800 CSM-101 capturado y reprogramado por John Connor y enviado al pasado para proteger a Sarah Connor y a él mismo de joven.",
  vista_en: 3.years.ago
}])

p "Creadas #{Pelicula.count} películas"Code language: Ruby (ruby)

Primero, borras todas las películas para tener un estado limpio y añades tres películas pasando un array al método create. El archivo de semillas usa ActiveSupport de Rails, para usar esos comandos X.ago tan útiles de Ruby para definir fechas.

Al final, hay un pequeño feedback sobre el total de películas creadas. ¡Vamos a ejecutarlo!

$ rails db:seed
"Creadas 3 películas"Code language: Shell Session (shell)

Puedes ejecutar este comando tantas veces como necesites. Se borran los registros existentes gracias a la primera línea que contiene el destroy.

Para comprobarlas, puedes usar rails runner:

$ rails runner 'p Pelicula.pluck :titulo'
["Soul", "El Señor de los Anillos: La Comunidad del Anillo", "Terminator 2"]Code language: Shell Session (shell)

Usando una tarea personalizada de Rails para sembrar datos reales

Todas tus semillas son consideradas datos de desarrollo, no datos finales para uso en producción. Así que, no siembres en producción de la manera que acabas de hacer. ¡Sobretodo porque el primer paso elimina todas las películas!

Para sembrar datos reales, es mejor crear una tarea personalizada de Rails. Vamos a generar una para añadir géneros.

Primero genera el modelo y luego migra la base de datos. Finalmente crea la tarea.

rails g model Genero nombre

rails db:migrate

rails g task peliculas sembrar_generosCode language: Shell Session (shell)

Este comando crea un archivo rake de películas en el directorio lib/tasks conteniendo la tarea sembrar_generos.

Copia el código de abajo y pégalo en lib/tasks/peliculas.rake:

namespace :peliculas do
  desc "Siembra géneros"
  task sembrar_generos: :environment do
    Genero.create!([{
      nombre: "Acción"
    },
    {
      nombre: "Ciencia Ficción"
    },
    {
      nombre: "Aventura"
    }])

    p "Creados #{Genero.count} géneros"
  end
endCode language: Ruby (ruby)

Ya aparece en la lista de comandos de Rails:

$ rails -T peliculas
rake peliculas:sembrar_generos  # Siembra génerosCode language: Shell Session (shell)

¡Hora de ejecutarla!

$ rails peliculas:sembrar_generos
"Creados 3 géneros"Code language: Shell Session (shell)

Cargar semillas usando la consola

La consola es útil para jugar con tus datos. Vamos a abrirla:

$ rails c
Loading development environment (Rails 6.1.3)Code language: Shell Session (shell)

¿Sabías que puedes cargar y acceder a tus semillas desde dentro? Prueba esto:

Rails.application.load_seedCode language: Ruby (ruby)

Jugando con datos usando la consola en modo sandbox

A veces necesitarás ejecutar comandos destructivos en datos reales en tu entorno de desarrollo o producción sin que los cambios sean permanentes. Es como un modo seguro donde puedes hacer lo que quieras y volver a un estado anterior.

Este modo se llama sandbox, y puedes acceder a él con el comando rails c --sandbox

Esta técnica es útil para depurar una base de datos real, como por ejemplo cuando un usuario dice que intenta actualizar su nombre de perfil y ve un error raro. Podrías reproducir ese error directamente usando el modo sandbox sin que afecte a los datos reales.

Cargando más semillas usando Faker

Si necesitas, por ejemplo, 100 películas, puedes reemplazar tu archivo app/db/seeds.rb con esto:

Pelicula.destroy_all

100.times do |index|
  Pelicula.create!(titulo: "Título #{index}",
                director: "Director #{index}",
                sinopsis: "Sinopsis #{index}",
                vista_en: index.days.ago)
end

p "Creadas #{Pelicula.count} películas"Code language: Ruby (ruby)

Ahora ejecuta rails db:seed:

$ rails db:seed              
"Creadas 100 películas"Code language: Shell Session (shell)

Pero el resultado no parece nada realista:

$ rails runner 'p Pelicula.select(:titulo, :director, :sinopsis).last'
#<Pelicula id: nil, titulo: "Título 99", director: "Director 99", sinopsis: "Sinopsis 99">Code language: Shell Session (shell)

Hora de usar Faker, una gema que genera valores aleatorios. Añádela en el grupo de desarrollo en tu Gemfile:

group :development, :test do
  # ...

  gem 'faker'
endCode language: Ruby (ruby)

Ejecuta bundle install y reemplaza app/db/seeds.rb con esto:

Pelicula.destroy_all

100.times do |index|
  Pelicula.create!(titulo: Faker::Lorem.sentence(word_count: 3, supplemental: false, random_words_to_add: 0).chop,
                director: Faker::Name.name,
                sinopsis: Faker::Lorem.paragraph,
                vista_en: Faker::Time.between(from: 4.months.ago, to: 1.week.ago))
end

p "Creadas #{Pelicula.count} películas"Code language: Ruby (ruby)

Prueba otra vez:

$ rails db:seed              
"Creadas 100 películas"
$ rails runner 'p Pelicula.select(:titulo, :director, :sinopsis, :vista_en).last'
#<Pelicula id: nil, titulo: "Toy Story 2", director: "Michael Dickinson", sinopsis: "Modi esse et at eum deserunt harum qui itaque reru...", vista_en: "2020-11-18">Code language: Shell Session (shell)

¡Mucho mejor!

Conclusión

Sembrar la base de datos mientras desarrollas la aplicación es esencial, porque te dará la sensación de estar trabajando con datos reales.

También, conocer las herramientas disponibles para trabajar con semillas es más cómodo y productivo, así que vale la pena invertir tiempo en aprenderlas.

Versión en video

https://youtu.be/_L36H5Pkd9I

Written by

David Morales

Computer Engineer

Teaching my software engineering knowledge in a creative way.

Would you like to get the 10 Ninja Keys of the Developer?

An exclusive PDF for Newsletter subscribers.

You will also be notified of future articles and affordable courses (in the pipeline) that will turn you into a ninja developer.

View privacy information

Leave a reply

Please fill in all fields.

Your email address will not be published.

View privacy information