sábado, 18 de julio de 2009

Conectar una aplicación rails a varias bases de datos simultáneamente

Se puede conectar una aplicación rails a varias bases de datos a la vez, eso sí, hay que tener un especial cuidado con el rendimiento de la aplicación, aunque ActiveRecord nos provee una interfaz transparente a la hora de acceder a los modelos.

Suponiendo como ejemplo que tenemos dos modelos (Post y Comment) y este último está localizado en una base de datos externa, se puede configurar rails de la siguiente forma:

1) Primero, creamos un fichero de configuración para la conexión a la nueva base de datos (config/external_database.yml).

development:
adapter: mysql
database: test
username: root
password:

production:
adapter: mysql
database: test
username: root
password:

2) Después, creamos un módulo para encapsular la lectura del fichero y la nueva conexión.

module ExternalDatabase
def self.included(base)
config = YAML.load(File.open('config/external_database.yml'))

if config and ENV['RAILS_ENV']
base.establish_connection(config[ENV['RAILS_ENV']])
else
raise 'External Database not configured'
end
end
end

3) Por último, incluimos en los modelos que van a la base de datos externa el módulo que hemos creado.

class Comment < ActiveRecord::Base
include ExternalDatabase

belongs_to :post
end

Con esto ya podemos utilizar los modelos aunque cada uno esté en una base de datos diferente.

Comment.find(:all, :include => :post)

sábado, 11 de julio de 2009

Diferencias de rendimiento entre eval y send

La metaprogramación en ruby permite mucha expresividad y flexibilidad, aún así hace caer bastante el rendimiento.

A pesar de eso, lo más importante es evitar en la medida de lo posible eval ya que es bastante más lento.

Al hacer una llamada a send la máquina virtual de ruby tiene que buscar el nombre del método que se le pasa como parámetro y ejecutarlo.

En cambio, al hacer un eval además de lo anterior la máquina virtual necesita parsear la cadena y después ejecutar el código.


Benchmark.bm{|x| x.report{100000.times{eval('Post.scopes')}}}
user system total real
0.410000 0.000000 0.410000 ( 0.410306)

Benchmark.bm{|x| x.report{100000.times{Post.send('scopes')}}}
user system total real
0.140000 0.000000 0.140000 ( 0.144820)