Cómo conectarse a un servidor SQL Server 2005 con ActiveRecord 3.0

Recientemente me encontré en la tarea de implementar algún tipo de conectividad con un servidor Microsoft SQL Server para extraer información muy específica que pudiera publicarse en el sitio web de un buen cliente. El sitio web en sí está desarrollado en PHP, pero exponer un servicio web desde la Intranet del cliente usando ese lenguaje para conectarse con el servidor SQL Server no parecía ser la mejor solución a simple vista: Microsoft sí ofrece un "driver" de SQL Server para PHP5, pero éste no es incluído por defecto con la distribución oficial de PHP; sin contar con mi abversión a todo lo que tenga la marca de "MS".

Finalmente decidí montar un pequeño servicio web usando Sinatra y un stack Ruby completo, aprovechando mis recientes exitosas experiencias con ese mínimo "framework". En este artículo explicaré cómo lo hice, para futura referencia personal y de todos los que necesiten hacer algo parecido.

Sale DataMapper, entra ActiveRecord

Al principio mi idea fué usar DataMapper, el otro popular ORM para Ruby que también soporta SQL Server; pero me dí de bruces contra una pared cuando su "adaptador" dm-sqlserver-adapter tenía entre sus dependencias una gema que a su vez sólo está disponible para la plataforma Java (?):

ERROR:  Could not find a valid gem 'do_sqlserver' (>= 0), here is why:
          Found do_sqlserver (0.10.3), but was for platform java

Desalentado por perder la oportunidad de usar con una finalidad práctica DataMapper por primera vez, volví al fiel ActiveRecord, ahora también actualizado a su versión 3.0 junto con Rails. ActiveRecord también soporta SQL Server, y todas sus dependencias para hacerlo pueden satisfacerse fácilmente en los servidores Ubuntu 8.04 LTS de producción que disponía para la tarea.

Instalación del soporte para SQL Server en Ubuntu

Todo el proceso de instalación de ActiveRecord con soporte de SQL Server en Ubuntu se encuentra afortundamente muy bien documentado en su wiki. Básicamente, y como mínimo, es necesario instalar los siguientes paquetes:

  • tdsodbc
  • odbcinst
  • unixodbc
  • unixodbc-dev (dependencia para la gema ruby-odbc)

Si en lugar de Ubuntu 8.04 LTS usamos el más reciente Ubuntu 10.04 LTS también debemos instalar estos paquetes:

  • freetds-bin
  • freetds-common

Luego deberemos agregar, como superusuario, una entrada en el archivo /etc/freetds/freetds.conf para el servidor SQL Server al que queremos conectarnos. Por ejemplo, en mi caso es mas o menos así:

[mordor]
host = 192.168.1.124
port = 1433
tds version = 7.0

La versión de TDS, el protocolo Tabular DataStream, es importante y arriba hace referencia a la versión usada en SQL Server 2005 (que seguramente será la misma para su más reciente versión 2008, pero quizás no para las anteriores).

También tenemos que asegurarnos que el archivo /etc/odbcinst.ini tenga como mínimo estos contenidos:

[FreeTDS]
Description     = TDS driver (Sybase/MS SQL)
Driver          = /usr/lib/odbc/libtdsodbc.so
Setup           = /usr/lib/odbc/libtdsS.so
CPTimeout       =
CPReuse         =
FileUsage       = 1

Por último agregamos una entrada en archivo /etc/odbc.ini con los datos de la base de datos a que deseamos conectarnos:

[mordor_connection]
Driver = FreeTDS
Description     = ODBC connection via FreeTDS
Trace           = No
Servername      = mordor
Database        = saruman-bd

El valor de "Servername" debe corresponder al nombre de la entrada del servidor que creamos en el archivo /etc/freetds/freetds.conf más arriba y el de "Database" debe ser una base de datos en ese servidor creada y para la cual tengamos previamente creado un usuario con el cual poder conectarnos.

Ahora podemos hacer una prueba de conexión. Por ejemplo, suponiendo que nuestro usuario de SQL Server es "frodo" y su clave es "comarca", intentamos ejecutar el siguiente comando:

$ isql -v mordor_connection frodo comarca

Si obtenemos un mensaje como el siguiente todos los pasos anteriores resultaron exitosos y podemos continuar con la instalación de todas las gemas necesarias para conectarnos al servidor SQL Server desde Ruby:

+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+

Instalación de ActiveRecord 3.0

Primero que todo, ActiveRecord 3.0 requiere como mínimo Ruby 1.8.7 para funcionar. Pero como Ubuntu 8.04 LTS sólo incluye un paquete de Ruby 1.8.6, será necesario instalar el paquete de Ruby 1.8.7 Enterprise Edition como es muy generosamente ofrecido por el hoster británico Brightbox. Las instrucciones para hacerlo son muy sencillas y se encuentran aquí. Notar que para agregar los repositorios de Brightbox exitosamente a nuestra lista de APT debemos también instalar sus claves GPG como se explica en su wiki.

El "infierno de las dependencias" también es aplicable a las gemas de Ruby, y lo más inteligente que podemos hacer para librarnos de él es usar Bundler para cualquier proyecto que iniciemos en este lenguaje. Como ejemplo, estos son los contenidos de mi Gemfile para instalar la gema de ActiveRecord 3.0 y todas sus dependencias ejecutando únicamente el comando "bundle install":

source :rubygems

gem 'sinatra'
gem 'builder', '~> 2.1'
gem 'ruby-odbc'
gem 'activerecord-sqlserver-adapter', '~> 3.0'

La gema de "ruby-odbc" debe instalar unas extensiones que debe compilar antes, por lo que antes de ejecutar "bundle install" debemos asegurarnos de tener instalado el paquete "build-essential" de Ubuntu.

Probándolo todo en Ruby

Ahora finalmente podemos hacer un pequeño script para probar cómo ActiveRecord 3.0 se conecta al servidor de SQL Server desde nuestro fiel servidor Ubuntu. Sólo como ejemplo, la cosa sería más o menos así:

ActiveRecord::Base.establish_connection(
    :adapter  => "sqlserver",
    :host     => "192.168.1.124",
    :dsn      => 'mordor_connection',   # entrada en /etc/odbc.ini 
    :database => "saruman-bd",
    :username => "frodo",
    :password => "comarca"
)

class Orden < ActiveRecord::Base
  set_table_name 'diamov'
  set_primary_key 'seq'
end

class Movimiento < ActiveRecord::Base
  set_table_name 'dmov_d'
end

puts Orden.first.inspect
puts Movimiento.first.inspect

Obviamente, la parte más divertida es programar el servicio con Sinatra para construir algo útil con todo lo que hicimos hasta ahora. Pero si llegaste a leer todo hasta aquí, ¡no me cabe duda de que eres tan capaz como yo de hacerlo! :)

blog comments powered by Disqus

 

RSS Blog