Hace un tiempo en un experimento estábamos construyendo un sitio web para hacer sitios web, la parte compleja de este sitio era que el usuario que creaba su página web quería poner formularios de registros a su antojo y no teníamos como saber cuantos datos y como iba a querer guardarlos. En particular las bases de datos SQL como MySQL y PostgreSQL sufren este problema, necesitas conocer la estructura de antemano para poder guardar datos, pero existe una solución y lo mejor de todo es que está incorporada nativamente dentro de Rails y Postgres y consiste en ocupar la extensión HStore.
Arreglos en PostgreSQL
Para un ejemplo básico vamos a crear un proyecto de Rails desde cero, vamos a crear un modelo FOO con el campo bar, eso si, [symple_highlight color=»red»]es importante estar ocupando postgreSQL en lugar de sqlite [/symple_highlight]
rails g model foo bar:text
Antes de hacer la migración vamos a revisar el archivo de migración generado y modificarlo para especificar que vamos a guardar un arreglo y que por defecto es un arreglo vacío.
t.text :bar, array: true, default: []
Ahora podemos correr las migraciones con
rake db:migrate
y podemos entrar al rails console para crear un objeto foo y guardar un arreglo.
Foo.create(bar:[1,2,3,4,5])
ahora el arreglo bar se comparta como un arreglo común de ruby y podemos utilizarlo así:
foo = Foo.create(bar:[1,2,3,4,5])
foo.bar[1]
Hashes en PostgreSQL
Para guardar un diccionario o hash dentro de PostgreSQL primero necesitamos activar la extensión hstore de postgres primero vamos a generar una migración para agregar la columna baz del tipo hstore al modelo de Foo
rails g migration addBazToFoo baz:hstore
luego antes de correr la migración tenemos que entrar y modificarle, primero para activar la extensión hstore y luego pare decir que la columna baz ingrese por defecto un hash vacío.
def change
enable_extension 'hstore'
add_column :foos, :baz, :hstore, default: {}, null: false
end
luego corremos las migraciones.
rake db:migrate
y ahora podemos entrar a la consola de rails para probar los hashs
rails c
foo = Foo.create(baz: {"key" => "value"})
foo.baz["key"]
Rescatar datos de un hash es sencillo cuando se hace como es el caso anterior, pero que pasa si queremos hacer una consulta en base a uno de los valores dentro del hash, esto también es posible, por ejemplo si queremos rescatar todos los Foo cuyo key del hash tiene un valor especifico también podemos hacerlo.
Para eso voy a repetir el experimento anterior creando el modelo User, con dos campos, name y favs donde en favs vamos a guardar las cosas favoritas del usuario, las cuales no sabemos todavía cuales son (si, podríamos hacer una tabla para los favoritos y realizar una relación de muchos a muchos con la de usuarios, pero lo que queremos hacer ahora es probar el hstore) entonces creamos el modelo de usuarios desde el bash:
rails g model user name:string favs:hstore
y luego abrir el archivo de la migración el cual debería estar así:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.hstore :favs, default: {}
t.timestamps null: false
end
end
end
(no es necesario habilitar nuevamente el modo hstore, lo hicimos en la migración pasada y se hace sólo una vez) ahora entramos nuevamente a rails console y empezamos a crear los primeros usuarios para hacer las pruebas
User.create(name: "Diego Arias", favs:{"band": "Britney Spears", "movie": "Bridget Jones"})
User.create(name: "Nicolás Melgarejo", favs:{"band": "Madonna", "movie": "Twilight"})
User.create(name: "Juan Cristobal Pazos", favs:{"band": "Shakira", "movie": "Twilight"})
y ahora procedemos a hacer las consultas: Para rescatar a los usuarios cuya banda favorita sea Britney Spears, debemos hacerlo así:
User.where("favs->'band' = ?", "Britney Spears")
Para rescatar a los usuarios cuya película favorita sea Twilight con
User.where("favs->'movie' = ?", "Twilight")
Ahora ocupando hstore y los arrays de Postgres puedes guardar datos sin necesidad de tener una estructura previamente definida, no se aconseja ocuparlo para no modelar el sitio, pero esto es especialmente útil cuando no sabes de antemano que es lo que tendrás que guardar.
Gonzalo Sánchez
Artículos relacionados
1 Comentario
Deja una respuesta
Recibe los artículos más leidos y beneficios especiales de nuestra academia
Empieza a trabajar en los roles digitales mejor pagados
Fórmate de manera práctica, e intensiva, con sesiones en vivo de forma flexible y efectiva. Te acompañamos desde que partes hasta que encuentras trabajo.
[…] el tutorial anterior vimos como utilizar los tipos de datos hstore de postgres para guardar directamente un hash, en […]