La abundancia de lenguajes de programación es algo maravilloso. Gracias a esto, podemos elegir el apropiado para atacar el problema que deseamos resolver. En mi opinión, lo más importante de un lenguaje es, precisamente, la razón de su existencia;
la tracción que tiene con su comunidad y qué tanta satisfacción y flexibilidad me da cuando veo el resultado de mi automatización.
En este artículo te mostraré la magia detrás de
Ruby y ActiveRecord. En otras palabras, te mostraré cómo un programador puede convertirse en un mago cuando usa las gemas correctas.
Ruby
Entre los más populares, tenemos este lenguaje completamente orientado a objetos. Pero entre más aprendes Ruby, irás descubriendo nuevas posibilidades que nunca se te hubieran ocurrido. Por ejemplo,
¿qué sucede cuando defines una clase que hereda de ActiveRecord::Base? ¿Por qué funciona mágicamente? Y si aprendes qué sucede, ¿qué tan complejo sería implementar mecanismos similares con tu propio código?
Al entender y seguir diferentes conceptos de Ruby, poco a poco lo irás comprendiendo. Lo mismo pasa si deseas incorporar el paradigma funcional y otras cosas más.
Cómo Hacer Magia con Magia
Hay muchas maneras de hacer magia con tu lenguaje.
Lo importante es qué tan complejo es hacerlo. Afortunadamente, la filosofía de Ruby es no subestimar el factor humano. Y gran parte del corazón de su funcionamiento viene del diseño de su modelo de objetos.
Esta modelación, enmendada con la sintaxis para manipularlo durante ejecución, es lo que nos permite escribir código -mágico- o formalmente,
metaprogramar de una manera fácil y alegre.
Si tomamos la decisión de persistir nuestras entidades en la base de datos, podemos usar la magia de la popular gema
ActiveRecord. Recordemos que semejante gema también está incorporada por defecto en todo proyecto con Rails.
Tenemos el siguiente modelo:
[ruby]class Food < ActiveRecord::Base
end[/ruby]
Deseamos crear un alimento y persistirlo en la base de datos:
[ruby]alimento = Food.new
alimento.name = "Arepa venezolana"
alimento.purchased = false
alimento.save
(0.3ms) begin transaction
SQL (1.2ms) INSERT INTO "foods" ("name", "purchased", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Arepa venezolana"], ["purchased", "f"], ["created_at", "2015-05-27 22:03:02.930899"], ["updated_at", "2015-05-27 22:03:02.930899"]]
(8.9ms) commit transaction[/ruby]
¡Funciona! Pero,
¿dónde están las definiciones de los métodos como #save, #name=, y #purchased=? ¡Magia!
Ganchos y Metaprogramación
Estás ante la presencia de
código que escribe código. En Ruby, cuando heredas de una clase, es posible ejecutar código mediante ganchos como
self.inherited(hijo) dentro de su definición:
[ruby]class Macronutriente
def self.inherited(hijo)
puts "!Me están heredando! fue #{hijo}"
end
end
class Proteina < Macronutriente; end
class Carbohidrato < Macronutriente; end
class Grasa < Macronutriente; end[/ruby]
Ejecutas el código y obtendrás:
[ruby]¡Me están heredando! fue Proteina
¡Me están heredando! fue Carbohidrato
¡Me están heredando! fue Grasa[/ruby]
En los ganchos es donde ActiveRecord participa. Es decir, en el momento en el que heredas de Base en el módulo de ActiveRecord
ActiveRecord::Base; lo que hace la gema es extraer el nombre de la clase mediante introspección.
Ya que la obtiene, encuentra una tabla/relación con el nombre en plural -
foods en este caso- en el esquema de la base de datos. Esto para finalmente descubrir los atributos de la tabla y autogenerar los métodos
#name, #name=, #purchased, #purchased=, #created_at, #created_at=, #updated_at, #updated_at=, y muchos más.
¡Todo esto durante la ejecución del programa!
Reproduce el Ejercicio en tu Máquina
ActiveRecord es una gran gema. Hasta ahora sólo hemos definido un modelo heredando de Base; pero ¿en qué momento creamos la base de datos con la tabla? La respuesta es simple, c
uando incorporamos la gema debemos de indicarle a qué base de datos conectarse, cuál es, y cómo.
Afortunadamente, cuando generas una aplicación en Rails todo viene configurado. Es decir, el archivo donde se ingresa la información de las bases de datos lo encuentras en
config/database.yml.
También existe un suite de comandos para administrar tu base de datos, mejor conocido como
migraciones. Aunque, en realidad, son clases en Ruby donde cada migración hereda de
ActiveRecord::Migration.
¡Vayamos al ejemplo! Para poder replicarlo en Rails, debes hacerlo de la siguiente manera:
[ruby]$ rails new comeplatzi
$ cd comeplatzi
comeplatzi $ rails g model food name:string purchased:boolean
invoke active_record
create db/migrate/20150528001653_create_foods.rb
create app/models/food.rb
rake db:migrate[/ruby]
Después, abrimos la consola interactiva dentro del ámbito de nuestra aplicación de Rails:
[ruby]comeplatzi $ rails c[/ruby]
Y creamos el modelo y la persistimos en la base de datos.
[ruby]
alimento = Food.new
alimento.name = "Arepa venezolana"
alimento.purchased = false
alimento.save[/ruby]
Verifica el código generado cuando se usa el generador: La migración y el modelo.
¿Cómo Pruebo ActiveRecord Sin un Marco de Trabajo Como Rails?
En tal caso, debes de preparar la configuración tú mismo. Lo agradable es que
puedes configurar ActiveRecord para que trabaje con una base de datos en memoria (requiere menos ceremonia). Por lo que el siguiente fragmento lo puedes guardar en archivo y probarlo.
Usaremos
SQLite como adaptador y guardemos el código en un archivo
comeplatzi.rb
[ruby]require 'active_record'
require 'logger'
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
ActiveRecord::Base.logger = Logger.new $stdout
ActiveSupport::LogSubscriber.colorize_logging = false
ActiveRecord::Schema.define do
self.verbose = false
create_table :foods do |t|
t.string :name
t.boolean :purchased
end
end
class Food < ActiveRecord::Base; end
alimento = Food.new
alimento.name = "Pollito"
alimento.purchased = false
alimento.save[/ruby]
¡Pruébalo!
ruby comeplatzi.rb
Lograste ver de manera simplificada la agilidad que nos da el interactuar con bases de datos mediante la gema ActiveRecord; que usa las riquezas que ofrece Ruby como lenguaje para metaprogramar.
Ruby On Rails incorpora ActiveRecord por defecto. Y también puedes usar otras gemas para interactuar con MongoDB, Redis, etcétera. Si quieres aprender más sobre Ruby y Ruby On Rails, el
Curso Profesional de Platzi te ayudará a empezar la aventura.
¡Nos vemos en el curso!