
GemRailsApp: Primeros Hacks
Muy bien, luego del background e introducción, vamos a aplicar, paso por paso, el concepto dentro de nuestra aplicación rails.
Conceptualmente, cuanto menos modificaciones se hagan al código de Rails, tanto mejor.
Archivos de cada configuración
Lo primero que debemos hacer es determinar qué archivos serán específicos de cada configuración (INSTANCE). Databases, logs y configuración suenan bien para mí, así que cada instancia debería proveer:
config/database.yml→ La configuración de nuestra instancia
db/*→ limpio para mysql, pero útil para sqlite y sqlite3
log/*→ donde el usuario buscará errores en caso de que necesitemos recibir reportes
Dentro de la aplicación
El paso siguiente es determinar donde estos archivos toman importancia dentro de nuestra aplicación.
Tomaré como ejemplo el script de server (webrick) del directorio scripts y depuraré todas las llamadas desde ahí.
Primero encontramos que asigna la constante RAILS_ENV (enviroment) y luego carga el archivo config/environment.rb.
Luego en environment.rb, carga database.yml y establece una conexión mediante ActiveRecord:
...
# Environment-specific configuration.
require_dependency "environments/#{RAILS_ENV}"
ActiveRecord::Base.configurations = File.open("#{RAILS_ROOT}/config/database.yml") { |f| YAML::load(f) }
ActiveRecord::Base.establish_connection
...
Para luego configurar el LOGGER de acuerdo a la configuración del environment:
...
# Configure defaults if the included environment did not.
begin
RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.log")
RAILS_DEFAULT_LOGGER.level = (RAILS_ENV == 'production' ? Logger::INFO : Logger::DEBUG)
...
Hasta el momento, estos son los únicos lugares donde deberíamos insertar nuestro código específico para instancias, ¿verdad?
¿Qué encontramos en común?
Las líneas en environment.rb nos muestran que RAILS_ENV y RAILS_ROOT son las principales constantes que apuntan a configuraciones específicas.
El escenario ideal es modificar la menor cantidad de código posible, por tal motivo agregar condicionales (if) entre environment y logger no es una opción.
¿Que podemos hacer entonces?
Luego de definir RAILS_ENV, deberíamos agregar las siguientes líneas:
# Here we will define INSTANCE.
# in case isn't defined from ENV, we should default to RAILS_ROOT as fail-safe
# (in case we are in development mode, not gem-mode).
INSTANCE = ENV['INSTANCE'] || RAILS_ROOT
Ahora necesitamos modificar la ubicación desde la cual database.yml será cargado:
ActiveRecord::Base.configurations = File.open("#{RAILS_ROOT}/config/database.yml") { |f| YAML::load(f) }
Por:
ActiveRecord::Base.configurations = File.open("#{INSTANCE}/config/database.yml") { |f| YAML::load(f) }
Hacemos lo mismo con el logger:
RAILS_DEFAULT_LOGGER = Logger.new("#{RAILS_ROOT}/log/#{RAILS_ENV}.log")
Se convierte en:
RAILS_DEFAULT_LOGGER = Logger.new("#{INSTANCE}/log/#{RAILS_ENV}.log")
Poniendo a prueba la teoría
Configuramos la variable de entorno (mediante set en windows o export en linux) de tal manera que:
>set INSTANCE=path_absoluto_a_la_estructura_de_nuestra_instancia
>ruby script/server
Todo parece bien, incluso log/development.log es creado a donde INSTANCE esta apuntando, eso es bueno.
No olviden crear
database.ymldentro de su instancia. De lo contrario, la aplicación Rails no funcionará.