Posts Tagged ‘rails’

Gem + Rails + Ruby + Debian. ¿Cómo solucionarlo?

Saturday, June 21st, 2008

Comencé a conocer un poco más sobre este mundo llamado Ruby y me he quedado
bastante sorprendido. Al parecer es un problema recurrente el tema de las gemas y ubuntu. Por lo tanto paso a explicar mi experiencia y cómo lo solucione. Se pueden encontrar muchas explicaciones por Internet,
pero ninguna simple y concisa.

Tengo en cuenta que tienen ya instalado Ruby. Sólo me enfocaré en las Rubygems. Para esto lo primero crear nuestro propio repositorio de gemas. Por ejemplo


$ mkdir -p /home/user/.rubygems/repos

Una vez creada la ubicación de nuestro repositorio bajaremos el código fuente de RubyGems y lo instalaremos en la ubicación creada anteriormente (/home/user/.rubygems). Podemos encontrar las distintas versiones de RubyGems en RubyForge. Utilizo la versión 1.0.1 para ejemplificar la instalación y posterior explicación. Es muy probable que cuando lea este post se encuentre una versión más reciente de RubyGems.


$ wget http://rubyforge.org/frs/download.php/29548/rubygems-1.0.1.tgz
$ tar xzvf rubygems-1.0.1.tgz
$ cd rubygems-1.0.1
$ ruby setup.rb all --prefix=/home/user/.rubygems

El comando anterior instalará RubyGems y creará dentro de .rubygems dos carpetas (bin y lib), la importante aquí es bin, que es donde se encuentra el ejecutable de RubyGem

Nota: la instalación la estamos realizando en /home/user/.rubygems y no en /home/user/.rubygems/repos. Porque sólo estamos instalando RubyGems y no los gems.

Si verifican dentro de la carpeta bin el ejecutable se llama gem1.8, para comodidad he decidido hacer un link simbólico llamado gem


$ ln -s ./gem1.8 ./gem

Felicitaciones tenemos instalado RubyGems, pero ahora falta definir para el resto de las aplicaciones dónde está RubyGems y dónde el repositorio. Se logra definiendo las siguientes variables de entorno GEM_HOME y PATH

GEM_HOME
Declaramos en dónde se encuentra nuestro repositorio de gemas
PATH
Declaramos en dónde se encuentra RubyGems

Nos valdremos del comando export para definirlas


$ export GEM_HOME=/home/user/.rubygems/repos
$ export PATH=$PATH:/home/user/.rubygems/bin
$ export PATH=$PATH:/home/user/.rubygems/repos/bin

Expliquemos un poco lo que hemos hecho para los más despistados. Aquí hemos definido en dónde esta el repositorio de gemas, por lo tanto, todo programa que utilice gemas sabrá en dónde se encuentran. El segundo export hemos exportado la ejecución del RubyGems (gem) desde cualquier lado. El último export permite ejecutar alguna gema en particular (e.g. rails).

Nota: Para que las nuevas variables sean leídas hay que utilizar el siguiente comando:


$ source ~/.bashrc

Veamos un ejemplo. Si no hubiese definido las variables anteriores y realizo lo siguiente:


$ cd /home/a/un/lugar/lejos
$ gem
El programa «gem» no está instalado actualmente.  Puedes instalarlo escribiendo:
sudo apt-get install rubygems
Compruebe que tiene el componente 'universe' activado
bash: gem: orden no encontrada

Aparece como si no estaría instalado; el sistema no sabe en dónde hemos instalado RubyGems (/home/user/.rubygems/bin). Por lo tanto, al “exportar” esta ubicación podemos ejecutar RubyGems desde cualquier lado, sin que sea necesario estar dentro de /home/user/.rubygems/bin

Y por último si no hubiésemos definido el GEM_HOME el sistema no sabría en dónde están las gemas. Entonces por ejemplo si ejecutásemos RubyGems para instalar una gema, éste no sabría en dónde
instalarlo. Y sucedería lo siguiente


$ gem install rails

Bulk updating Gem source index for: http://gems.rubyforge.org
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions into the /usr/bin directory.

Una vez definida nuestras variables de entorno podemos hacer lo siguiente


$ gem install rails
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed rake-0.8.1
Successfully installed activesupport-2.0.2
Successfully installed activerecord-2.0.2
Successfully installed actionpack-2.0.2
Successfully installed actionmailer-2.0.2
Successfully installed activeresource-2.0.2
Successfully installed rails-2.0.2
7 gems installed
Installing ri documentation for rake-0.8.1...
Installing ri documentation for activesupport-2.0.2...
Installing ri documentation for activerecord-2.0.2...
Installing ri documentation for actionpack-2.0.2...
Installing ri documentation for actionmailer-2.0.2...
Installing ri documentation for activeresource-2.0.2...
Installing RDoc documentation for rake-0.8.1...
Installing RDoc documentation for activesupport-2.0.2...
Installing RDoc documentation for activerecord-2.0.2...
Installing RDoc documentation for actionpack-2.0.2...
Installing RDoc documentation for actionmailer-2.0.2...
Installing RDoc documentation for activeresource-2.0.2...

Nos crearía dentro de /home/user/.rubygems/repos ($GEM_HOME) los directorios: cache, doc, gems, specifications. Dentro gems, estará la gema rails y sus dependencias.

Nota: Con la variable de entorno GEM_HOME, podemos definir más de un repositorio de gemas, en caso de que tengamos múltiples repositorios, tendríamos que hacer: export GEM_HOME=$GEM_HOME:/hacia/el/otro/repositorio

Las variables establecidas anteriormente no son persistentes, o sea, deberíamos definirlas cada vez que reiniciamos la computadora. Para persistirlas:


$ echo "export GEM_HOME=/home/user/.rubygems/repos" >> /home/user/.bashrc
$ echo "export PATH=$PATH:/home/user/.rubygems/bin" >> /home/user/.bashrc
$ echo "export PATH=$PATH:/home/user/.rubygems/repos/bin" >> /home/user/.bashrc

Otra comprobación de las variables es con el comando


$ gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 1.0.1 (1.0.1)
  - RUBY VERSION: 1.8.5 (2006-08-25) [i486-linux]
  - INSTALLATION DIRECTORY: /home/user/.rubygems
  - RUBY EXECUTABLE: /usr/bin/ruby1.8
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86-linux
  - GEM PATHS:
     - /home/user/.rubygems
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :benchmark => false
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - http://gems.rubyforge.org

Como nota el procedimiento anterior soluciona los siguientes problemas al ejecutar Netbeans 6 en Debian (o Ubuntu)

  1. Your Ruby installation does not appear to have Ruby Gems installed. Cannot find “gem” command either in the interpreter’s folder or on the
    system path
  2. The gem repository is not writable as this user. Either install your gems elsewhere by changing Gem Home in the Ruby Plataform Manager to an alternative (and writable) repository or run as root, or manually change the gem repository file permissions, or build your own Ruby installation with user permissions.

Bibliografía

Problemas con Rails en Debian

Friday, June 20th, 2008

Acá dejo la solución a un error que ocurre al tratar de instalar Rails en Debian. Me base en un post[soulforged.net], que explica correctamente la solución del mismo, pero éste se basa en FreeBSD, de todos modos es un error propio de Ruby Gems y no del sistema operativo. El error en cuestión es

INFO: `gem install -y` is now default and will be removed
INFO: use –ignore-dependencies to install only the gems you list
ERROR: could not find rails locally or in a repository

Y sucede, una vez terminado de instalar Ruby y Ruby Gems, al trata de instalar
Rails. La solución es antes de intentar instalar Rails, ejecutar el siguiente
comando:


$ gem update --system

Es recomendado visitar el enlace que cité más arriba, porque trata sobre otros posibles errores y su solución.

Problemas con WEBrick en Debian

Friday, June 20th, 2008

Una vez que instalé Rails, y me propongo a levantar WEBrick (script/server). Me lanza el siguiente error:


$ script/server
=> Booting WEBrick...
/usr/lib/ruby/gems/1.8/gems/rails-2.0.2/lib/initializer.rb:159:in `require_frameworks': no such file to load -- openssl (RuntimeError)
        from /usr/lib/ruby/gems/1.8/gems/rails-2.0.2/lib/initializer.rb:88:in `process'
        from /usr/lib/ruby/gems/1.8/gems/rails-2.0.2/lib/initializer.rb:49:in `send'
        from /usr/lib/ruby/gems/1.8/gems/rails-2.0.2/lib/initializer.rb:49:in `run'
        from /var/proyect/rails/aplicacion/config/environment.rb:13
        from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:496:in `require'
        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
         ... 7 levels...
        from /usr/lib/ruby/gems/1.8/gems/rails-2.0.2/lib/commands/server.rb:39
        from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from script/server:3

Esto se soluciona instalando el siguiente paquete


# aptitude install libopenssl-ruby

Herencia en Rails

Friday, June 20th, 2008

Después de leer y reunir información de varios sitios pude entender como implementar la herencia en Ruby on Rails; utiliza el enfoque STI.

STI: En este enfoque cada modelo/entidad perteneciente a la jerarquía de la herencia se representa en una única tabla. Está tiene un atributo especial (columna) que identifica a qué modelo/entidad corresponde dicho registro/tupla.

Por lo tanto, tendremos una única tabla con todos los atributos de todos los modelos/entidades más un atributo especial.

Tuve problemas precisamente cuando tengo una herencia con más de un nivel, la solución es igual que tener un nivel de herencia. Dejo aquí un ejemplo ilustrativo del asunto.

Herencia citada en el ejemplo

Cada modelo podríamos asignarle los siguientes atributos

  • Vehiculo
    • nombre, del tipo String
  • Aereo
    • alas, del tipo Integer
  • Terrestre
    • ruedas, del tipo Integer
  • Auto
    • puertas, del tipo integer

Ahora creemos las cuatro clases en app/models las cuales quedarán con el siguiente aspecto

  • vehiculo.rb
    
    class Vehiculo < ActiveRecord::Base
    end
    
  • aereo.rb
    
    class Aereo < Vehiculo
    end
    
  • terrestre.rb
    
    class Terrestre < Vehiculo
    end
    
  • auto.rb
    
    class Auto < Terrestre
    end
    
    

Necesitamos crear un archivo migrate para mapear nuestros modelos a la base de datos (en este caso MySQL), este archivo tendría el siguiente aspecto:


class Ejemplo < ActiveRecord::Migration
  def self.up
    create_table :vehiculos do |t|
      t.column :nombre, :string
      t.column :alas, :integer
      t.column :ruedas, :integer
      t.column :puertas, :integer
      t.column :type, :string
    end
  end

  def self.down
    drop_table :vehiculos
  end
end

Indicaremos a Rails que implemente el esquema anterior, sólo bastará un rake:migrate. Esto nos genera la siguiente tabla



mysql> describe vehiculos;
+———+————–+——+—–+———+—————-+
| Field   | Type         | Null | Key | Default | Extra          |
+———+————–+——+—–+———+—————-+
| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
| nombre  | varchar(255) | YES  |     | NULL    |                |
| alas    | int(11)      | YES  |     | NULL    |                |
| ruedas  | int(11)      | YES  |     | NULL    |                |
| puertas | int(11)      | YES  |     | NULL    |                |
| type    | varchar(255) | YES  |     | NULL    |                |
+———+————–+——+—–+———+—————-+
6 rows in set (0.01 sec)

Por último probemos como Rails resuelve la herencia, para esto utilizaremos la consola (script/console). Ire creando objetos (que se mapearan como registros en la base de datos) de los distintos modelos/entidades.


>> a = Vehiculo.create
=> #<Terrestre id: 1, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Vehiculo">

>> b = Aereo.create
=> #<Terrestre id: 2, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Aereo">
>> c = Terrestre.create
=> #<Terrestre id: 3, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Terrestre">
>> d = Auto.create
=> #<Auto id: 4, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Auto">

Como se puede ver, según el tipo de modelo creado, Rails establece el valor de la columna type. Ahora haré una serie de find, así se podrá ver cómo soluciona la herencia Rails.


>> Vehiculo.find :all
=> [#><Vehiculo id: 1, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: nil>, #<Aereo id: 2, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Aereo">, #<Terrestre id: 3, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Terrestre">, #<Auto id: 4, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Auto">]

Acá indiqué que me traiga todos los Vehiculos, es lo que se esperaba, me trajo todo los registros, ya que cada modelo hereda de Vehiculo y por la herencia cada modelo es un vehiculo.


>> Aereo.find :all
=> [#<Aereo id: 2, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Aereo">]

Como cree un sólo registro del tipo Aereo, me trae ese único. Ahora veamos el problema que comenté al inicio del post


>> Terrestre.find :all
=> [#<Terrestre id: 3, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Terrestre">, #<Auto id: 4, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Auto">]

Bien, me ha traído los dos registros, acá es igual que en el primer find que mostré, ya que Auto es un Terrestre (por la herencia), por lo tanto Rails debe traerme también ese tipo de registros


>> Auto.find :all
=> [#<Auto id: 4, nombre: nil, alas: nil, ruedas: nil, puertas: nil, type: "Auto">]

De este modo podemos implementar, en Ruby on Rails, el concepto de herencia..