Romper las reglas: usar SQLite para hacer demostraciones de aplicaciones web
Publicado: 2022-03-10La mayoría de los usuarios potenciales querrán probar el software o el servicio antes de comprometer tiempo y dinero. Algunos productos funcionan muy bien simplemente dando a los usuarios una prueba gratuita, mientras que otras aplicaciones se experimentan mejor con datos de muestra ya implementados. A menudo, aquí es donde entra en juego la antigua cuenta demo.
Sin embargo, cualquiera que haya implementado alguna vez una cuenta de demostración puede dar fe de los problemas asociados. Ya sabe cómo funcionan las cosas en Internet: cualquiera puede ingresar datos (ya sea que tenga o no sentido para el producto) y existe una buena posibilidad de que el contenido agregado por usuarios anónimos o bots pueda ser ofensivo para otros. Claro, siempre puede restablecer la base de datos, pero ¿con qué frecuencia y cuándo? Y en última instancia, ¿eso realmente resuelve el problema? Mi solución para usar SQLite .
¿Por qué no usar SQLite para la versión de producción?
Se sabe comúnmente que SQLite no maneja múltiples subprocesos, ya que toda la base de datos se bloquea durante un comando de escritura, que es una de las razones por las que no debe usarlo en un entorno de producción normal. Sin embargo, en mi solución, se usa un archivo SQLite separado para cada usuario que hace una demostración del software. Esto significa que la limitación de escritura solo se limita a ese usuario, pero varios usuarios simultáneos (cada uno con su propio archivo de base de datos) no experimentarán esta limitación. Esto permite una experiencia controlada para el usuario que prueba el software y les permite ver exactamente lo que usted quiere que vean.
Este tutorial se basa en una solución del mundo real que he estado ejecutando con éxito para una aplicación web de demostración SaaS desde 2015. El tutorial está escrito para Ruby on Rails (mi marco de trabajo de elección) versión 3 y superior, pero los conceptos básicos deben ser capaz de adaptarse a cualquier otro lenguaje o framework. De hecho, dado que Ruby on Rails sigue el paradigma de software "convención sobre configuración", incluso puede ser más fácil de implementar en otros marcos, especialmente en lenguajes simples (como PHP) o marcos que no hacen mucho en términos de administrar las conexiones de la base de datos. .
Dicho esto, esta técnica es especialmente adecuada para Ruby on Rails. ¿Por qué? Porque, en su mayor parte, es "independiente de la base de datos". Lo que significa que debería poder escribir su código Ruby y cambiar entre bases de datos sin ningún problema.
Se puede descargar una muestra de una versión final de este proceso desde GitHub.
El primer paso: entorno de implementación
Llegaremos a la implementación más adelante, pero Ruby on Rails se divide de forma predeterminada en entornos de desarrollo, prueba y producción. Vamos a agregar a esta lista un nuevo entorno de demostración para nuestra aplicación que será casi idéntico al entorno de producción pero nos permitirá usar diferentes configuraciones de base de datos.
En Rails, cree un nuevo entorno duplicando el archivo config/environments/production.rb
y cámbiele el nombre demo.rb
. Dado que el entorno de demostración se utilizará en una configuración similar a la de producción, es posible que no necesite cambiar muchas opciones de configuración para este nuevo entorno, aunque sugeriría cambiar config.assets.compile
de false
a true
, lo que facilitará la prueba local sin tener que precompilar.
Si está ejecutando Rails 4 o superior, también deberá actualizar config/secrets.yml
para agregar una secret_key_base
para el entorno de demostración. Asegúrese de hacer que esta clave secreta sea diferente a la producción para garantizar que las sesiones sean únicas entre cada entorno, lo que protege aún más su aplicación.
A continuación, debe definir la configuración de la base de datos en config/database.yml
. Si bien el entorno de demostración utilizará principalmente la base de datos duplicada que cubriremos en la siguiente sección, debemos definir el archivo de base de datos predeterminado y la configuración que se usará para nuestra demostración. Agregue lo siguiente a config/database.yml
:
demo: adapter: sqlite3 pool: 5 timeout: 5000 database: db/demo.sqlite3
En Rails, es posible que también desee verificar su Gemfile
para asegurarse de que SQLite3 esté disponible en el nuevo entorno de demostración. Puede configurar esto de varias maneras, pero puede verse así:
group :development, :test, :demo do gem 'sqlite3' end
Una vez que la base de datos está configurada, debe rake db:migrate RAILS_ENV=demo
y luego sembrar datos en la base de datos como desee (ya sea desde un archivo semilla, ingresando manualmente nuevos datos o incluso duplicando el archivo development.sqlite3
). En este punto, debe asegurarse de que todo funcione ejecutando rails server -e demo
desde la línea de comandos. Mientras ejecuta el servidor en el nuevo entorno de demostración, puede asegurarse de que sus datos de prueba sean como los desea, pero siempre puede volver y editar ese contenido más tarde. Al agregar su contenido a la base de datos de demostración, recomendaría crear un conjunto limpio de datos para que el archivo sea lo más pequeño posible. Sin embargo, si necesita migrar datos de otra base de datos, le recomiendo YamlDb, que crea un formato independiente de la base de datos para volcar y restaurar datos.
Si su aplicación Rails se ejecuta como se esperaba, puede continuar con el siguiente paso.
El segundo paso: usar la base de datos de demostración
La parte esencial de este tutorial es poder permitir que cada sesión use un archivo de base de datos SQLite diferente. Normalmente, su aplicación se conectará a la misma base de datos para cada usuario, por lo que se necesitará código adicional para esta tarea.
Para comenzar a permitir que Ruby on Rails cambie de base de datos, primero debemos agregar los siguientes cuatro métodos privados en application_controller.rb
. También deberá definir un filtro anterior para el método set_demo_database
para que se llame a la lógica que hace referencia a la base de datos de demostración correcta en cada carga de página.
# app/controllers/application_controller.rb # use `before_filter` for Rails 3 before_action :set_demo_database, if: -> { Rails.env == 'demo' } private # sets the database for the demo environment def set_demo_database if session[:demo_db] # Use database set by demos_controller db_name = session[:demo_db] else # Use default 'demo' database db_name = default_demo_database end ActiveRecord::Base.establish_connection(demo_connection(db_name)) end # Returns the current database configuration hash def default_connection_config @default_config ||= ActiveRecord::Base.connection.instance_variable_get("@config").dup end # Returns the connection hash but with database name changed # The argument should be a path def demo_connection(db_path) default_connection_config.dup.update(database: db_path) end # Returns the default demo database path defined in config/database.yml def default_demo_database return YAML.load_file("#{Rails.root.to_s}/config/database.yml")['demo']['database'] end
Dado que cada sesión del servidor tendrá una base de datos diferente, almacenará el nombre de archivo de la base de datos en una variable de sesión. Como puede ver, estamos usando session[:demo_db]
para rastrear la base de datos específica para el usuario. El método set_demo_database
controla qué base de datos usar al establecer la conexión a la base de datos establecida en la variable de sesión. El método default_demo_database
simplemente carga la ruta de la base de datos como se define en el archivo de configuración database.yml
.
Si está utilizando un lenguaje simple, en este punto probablemente pueda simplemente actualizar su secuencia de comandos de conexión de base de datos para apuntar a la nueva base de datos y luego pasar a la siguiente sección. En Rails, las cosas requieren algunos pasos más porque sigue el paradigma de software de "convención sobre configuración".
El tercer paso: duplicar el archivo SQLite
Ahora que la aplicación está configurada para usar la nueva base de datos, necesitamos un disparador para la nueva sesión de demostración. En aras de la simplicidad, comience simplemente usando un botón básico "Iniciar demostración". También puede convertirlo en un formulario en el que recopile un nombre y una dirección de correo electrónico (para un seguimiento del equipo de ventas, etc.) o cualquier cantidad de cosas.
Siguiendo las convenciones de Rails, cree un nuevo controlador 'Demo':
rails generate controller demos new
A continuación, debe actualizar las rutas para que apunten a sus nuevas acciones de controlador, envolviéndolas en un condicional para evitar que se llame en el entorno de producción. Puede nombrar las rutas como desee o nombrarlas usando las convenciones estándar de Rails:
if Rails.env == 'demo' get 'demos/new', as: 'new_demo' post 'demos' => 'demos#create', as: 'demos' end
A continuación, agreguemos un formulario muy básico a views/demos/new.html.erb
. Es posible que desee agregar campos de formulario adicionales para capturar:
<h1>Start a Demo</h1> <%= form_tag demos_path, method: :post do %> <%= submit_tag 'Start Demo' %> <% end %>
La magia ocurre en la acción de create
. Cuando el usuario se envía a esta ruta, la acción copiará el archivo demo.sqlite3
con un nuevo nombre de archivo único, establecerá las variables de la sesión, iniciará sesión con el usuario (si corresponde) y luego redirigirá al usuario a la página adecuada (llamaremos a esto el 'tablero').
class DemosController < ApplicationController def new # Optional: setting session[:demo_db] to nil will reset the demo session[:demo_db] = nil end def create # make db/demos dir if doesn't exist unless File.directory?('db/demos/') FileUtils.mkdir('db/demos/') end # copy master 'demo' database master_db = default_demo_database demo_db = "db/demos/demo-#{Time.now.to_i}.sqlite3" FileUtils::cp master_db, demo_db # set session for new db session[:demo_db] = demo_db # Optional: login code (if applicable) # add your own login code or method here login(User.first) # Redirect to wherever you want to send the user next redirect_to dashboard_path end end
Ahora debería poder probar el código de demostración localmente iniciando una vez más el servidor usando rails server -e demo
.
Si ya tenía el servidor en ejecución, deberá reiniciarlo para cualquier cambio que realice, ya que está configurado para almacenar en caché el código como el servidor de producción.
Una vez que todo el código funcione como se esperaba, confirme los cambios en su control de versión y asegúrese de confirmar el archivo demo.sqlite3
, pero no los archivos en el directorio db/demos
. Si está utilizando git, simplemente puede agregar lo siguiente a su archivo .gitignore
:
Si desea recopilar información adicional del usuario de demostración (como el nombre o el correo electrónico), es probable que desee enviar esa información a través de una API a su aplicación principal o a algún otro canal de ventas, ya que su base de datos de demostración no será confiable. (se reinicia cada vez que se vuelve a implementar).
!/db/demo.sqlite3 db/demos/*
Paso final: implementación de su servidor de demostración
Ahora que tiene su configuración de demostración funcionando localmente, obviamente querrá implementarla para que todos puedan usarla. Si bien cada aplicación es diferente, recomendaría que la aplicación de demostración viva en un servidor separado y, por lo tanto, se domine como su aplicación de producción (como demo.myapp.com). Esto asegurará que mantenga los dos entornos aislados. Además, dado que el archivo SQLite se almacena en el servidor, los servicios como Heroku no funcionarán ya que no proporciona acceso al sistema de archivos. Sin embargo, aún puede utilizar prácticamente cualquier proveedor de VPS (como AWS EC2, Microsoft Azure, etc.). Si le gusta la comodidad automatizada, hay otras opciones de Plataformas como servicio que le permiten trabajar con VPS.
Independientemente de su proceso de implementación, es posible que también deba verificar que la aplicación tenga los permisos de lectura/escritura adecuados para su directorio donde almacena los archivos SQLite de demostración. Esto podría manejarse manualmente o con un enlace de implementación.
SQLite no funcionará para mí. ¿Qué pasa con otros sistemas de bases de datos?
No se crean dos aplicaciones iguales y tampoco lo son sus requisitos de base de datos. Al usar SQLite, tiene la ventaja de poder duplicar rápidamente la base de datos, además de poder almacenar el archivo en el control de versiones. Si bien creo que SQLite funcionará en la mayoría de las situaciones (especialmente con Rails), hay situaciones en las que SQLite podría no ser adecuado para las necesidades de su aplicación. Afortunadamente, aún es posible utilizar los mismos conceptos anteriores con otros sistemas de bases de datos. El proceso de duplicación de una base de datos será ligeramente diferente para cada sistema, pero describiré una solución para MySQL y existe un proceso similar con PostgreSQL y otros.
La mayoría de los métodos cubiertos anteriormente funcionan sin modificaciones adicionales. Sin embargo, en lugar de almacenar un archivo SQLite en su control de versiones, debe usar mysqldump
(o pg_dump
para PostgreSQL) para exportar un archivo SQL de cualquier base de datos que tenga el contenido que le gustaría usar para su experiencia de demostración. Este archivo también debe almacenarse en su control de versiones.
Los únicos cambios al código anterior se encontrarán en la acción demos#create
. En lugar de copiar el archivo SQLite3, la acción del controlador creará una nueva base de datos, cargará el archivo sql en esa base de datos y otorgará permisos para el usuario de la base de datos si es necesario. El tercer paso de otorgar acceso solo es necesario si el usuario administrador de su base de datos es diferente del usuario que usa la aplicación para conectarse. El siguiente código hace uso de los comandos estándar de MySQL para manejar estos pasos:
def create # database names template_demo_db = default_demo_database new_demo_db = "demo_database_#{Time.now.to_i}" # Create database using admin credentials # In this example the database is on the same server so passing a host argument is not require `mysqladmin -u#{ ENV['DB_ADMIN'] } -p#{ ENV['DB_ADMIN_PASSWORD'] } create #{new_demo_db}` # Load template sql into new database # Update the path if it differs from where you saved the demo_template.sql file `mysql -u#{ ENV['DB_ADMIN'] } -p#{ ENV['DB_ADMIN_PASSWORD'] } #{new_demo_db} < db/demo_template.sql` # Grant access to App user (if applicable) `mysql -u#{ ENV['DB_ADMIN'] } -p#{ ENV['DB_ADMIN_PASSWORD'] } -e "GRANT ALL on #{new_demo_db}.* TO '#{ ENV['DB_USERNAME'] }'@'%';"` # set session for new db session[:demo_db] = new_demo_db # Optional: login code (if applicable) # add your own login code or method here login(User.first) redirect_to dashboard_path end
Ruby, como muchos otros lenguajes, incluido PHP, le permite usar acentos graves para ejecutar un comando de shell (es decir, `ls -a`
) desde su código. Sin embargo, debe usar esto con precaución y asegurarse de que no se puedan insertar parámetros o variables de cara al usuario en el comando para proteger su servidor de código inyectado maliciosamente. En este ejemplo, estamos interactuando explícitamente con las herramientas de línea de comandos de MySQL, que es la única forma de crear una nueva base de datos. Esta es la misma forma en que el marco Ruby on Rails crea una nueva base de datos. Asegúrese de reemplazar ENV['DB_ADMIN']
y ENV['DB_ADMIN_PASSWORD']
con su propia variable de entorno o cualquier otra forma de establecer el nombre de usuario de la base de datos. Deberá hacer lo mismo para ENV['DB_USERNAME']
si su usuario administrador es diferente del usuario de su aplicación.
¡Eso es todo lo que se necesita para cambiar a MySQL! La ventaja más obvia de esta solución es que no tiene que preocuparse por los posibles problemas que puedan surgir debido a las diferentes sintaxis entre los sistemas de bases de datos.
Eventualmente, se toma una decisión final basada en la calidad y el servicio esperados, en lugar de la conveniencia y la velocidad, y no está necesariamente influenciada solo por el precio.
Pensamientos finales
Este es solo un punto de partida de lo que puede hacer con su nuevo servidor de demostración. Por ejemplo, su sitio web de marketing podría tener un enlace a "Probar la característica XYZ". Si no necesita un nombre o correo electrónico, puede vincular el método demos#create
con un enlace como /demos/?feature=xyz
y la acción simplemente redirigirá a la función y/o página deseada, en lugar del tablero en el ejemplo anterior.
Además, si usa SQLite para los entornos de desarrollo y demostración, tener siempre esta base de datos de muestra en el control de versiones les daría a todos sus desarrolladores acceso a una base de datos limpia para usar en desarrollo local, entornos de prueba o pruebas de control de calidad. Las posibilidades son infinitas.
Puede descargar una demostración completa desde GitHub.