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:

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:

Cambiar:

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.yml dentro de su instancia. De lo contrario, la aplicación Rails no funcionará.

A continuación: convenciones y versiones