Ruby on Rails

Enlaces

Performance Tunning

El lío del respond_with

Módulos interesantes

Instalación en Ubuntu

Algunas guías

Procedimiento Ubuntu <=13.04

  1. Instalar los paquetes: * ruby * ruby-dev * libsqlite3-dev * libmysqlclient-dev * nodejs * nodejs-dev
  2. Instalar RubyGems bajándolo de aquí y siguiendo las instrucciones de instalación de esa misma página.
  3. Instalar Bundler: * sudo gem install bundler
  4. Instalación de Rails: * sudo gem install rails
  5. Instalar passenger (el propio instalador da instrucciones sobre los paquetes necesarios): * sudo gem install passenger
  6. Instalar el módulo en Apache: * sudo passenger-install-apache2-module
  7. Tal y como indica la salida del comando anterior, hay que habilitar el módulo recién instalado por medio de la configuración de Apache. Se puede hacer añadiendo los dos siguientes ficheros:
#/etc/apache2/mods-available/passenger.load
LoadModule passenger_module /usr/lib/ruby/gems/1.9.1/gems/passenger-3.0.19/ext/apache2/mod_passenger.so
#/etc/apache2/mods-available/passenger.conf
PassengerRoot /usr/lib/ruby/gems/1.9.1/gems/passenger-3.0.19
PassengerRuby /usr/bin/ruby1.9.1

(las rutas contenidas en los ficheros anteriores dependerán de la instalación; la salida del comando que instala el módulo nos indica los valores correctos).

Finalmente hay que habilitar el módulo:

$ sudo a2enmod passenger

Y reiniciamos Apache:

$ sudo service apache2 restart

Procedimiento Ubuntu >=13.10

  1. Instalar los paquetes: * ruby * ruby-dev * libsqlite3-dev * libmysqlclient-dev * nodejs * nodejs-dev
  2. Instalar RubyGems bajándolo de aquí y siguiendo las instrucciones de instalación de esa misma página.
  3. Instalar Bundler: * sudo gem install bundler
  4. Instalación de Rails: * sudo gem install rails
  5. Instalar passenger siguiendo esta guía. Recomienda instalarlo con los paquetes de la distribución. A continuación se indica un resumen de los pasos.
  6. Instalar la clave PGP del repositorio que vamos a añadir: * sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
  7. Instalar el siguiente paquete: * apt-transport-https
  8. Crear el fichero /etc/apt/sources.list.d/passenger.list con el siguiente contenido: * deb https://oss-binaries.phusionpassenger.com/apt/passenger saucy main
  9. Actualizar el repositorio e instalar el siguiente paquete: * libapache2-mod-passenger

Buenas prácticas

Tips

Visibilidad de Helpers

Los métodos definidos en los módulos Helper (app/helpers/<controller>_helper.rb) son visibles en las vistas por defecto. Para que estén disponibles en los controllers hay que hacer un include. Si lo hacemos en el controller base (ApplicationController) estará disponibles en todos los controllers dado que éstos heredan de ApplicationController.

Mejora en rendimiento en Desarrollo

Rails 3.1 introdujo el concepto del asset pipeline. Desafortunadamente esto causa problemas de rendimiento en el entorno de desarrollo. Para mejorarlo se puede utilizar la tarea de precompilador siguiente:

$ bundle exec rake assets:precompile:nondigest

Esto provoca que los cambios en los ficheros asset no sean incluidos automáticamente cuando recargamos la página. Para forzar su refresco hay que volver a ejecutar el comando anterior.

Borrado de assets

Rails proporciona la siguiente tarea de precompilador que borrará el directorio public/assets, cosa que puede resultar útil antes de un commit.

$ bundle exec rake assets:clean

Esta orden puede solucionar el problema con el font-awesome, que en ocasiones se dibuja mal.

También puede merecer la pena incluir el directorio public/assets en el fichero .gitignore.

Actualización de paquetes

Comandos interesantes relacionados con las versiones de los paquetes y su gestión:

Muestra el mapa de rutas

$ bundle exec rake routes

Muestra todas las tareas

$ bundle exec rake -T

Instalación de gem

Tras la instalación de un gem generalmente hay que instalar y ejecutar las migraciones de base de datos con los siguientes comandos:

$ rake railties:install:migrations
$ rake db:migrate

Para instalar una versión específica de una gem hay que añadir el argumento --version, como por ejemplo:

$ gem install --version '3.0.13' passenger

Activar modo debug

Instalar primero la gem debugger:

$ sudo gem install debugger

Añadir al Gemfile lo siguiente (probablemente sólo sea necesario en el entorno de desarrollo):

group :development do
  gem 'debugger'
end

Insertar en el código una llamada a debugger en el punto del código donde queramos que se detenga la ejecución.

Finalmente para arrancar el servidor en modo debug:

$ bundle exec rails s --debugger

Lo anterior sirve para depurar sobre Webrick. Para hacerlo bajo Passenger seguir las instrucciones de este post (con la ayuda de este otro). De forma resumida consiste en ejecutar:

$ cd <app_root>
$ sudo gem install ruby-debug19

Generar un task con:

$ bundle exec rails g task myapplication restart

Añadir lo siguiente al final del fichero config/environments/development.rb:

if File.exists?(File.join(RAILS_ROOT,'tmp', 'debug.txt'))
  require 'ruby-debug'
  Debugger.wait_connection = true
  Debugger.start_remote
  File.delete(File.join(RAILS_ROOT,'tmp', 'debug.txt'))
end

Ejecutar:

$ bundle exec rake myapplication:restart DEBUG=true

Y una vez que hagamos una request para que se reinicie la aplicación ejecutar:

$ rdebug -c

Generación de un modelo

El siguiente comando creará un modelo para una entidad además de la migration correspondiente en la base de datos:

$ bundle exec rails g model spree/product_layout name:string view:string description:text

Path Helpers

Dada la siguiente definición de resources anidados:

resources :magazines do
  resources :ads
end

Alternativamente al uso de los path helpers habituales, cuando se pasa como argumento un objeto se puede dejar a Rails que decida automáticamente el path helper necesario, es decir las siguientes líneas serán equivalentes:

<%= link_to "Ad details", magazine_ad_path(@magazine, @ad) %>
<%= link_to "Ad details", url_for([@magazine, @ad]) %>

En helpers como link_to podemos indicar simplemente los objetos:

<%= link_to "Ad details", [@magazine, @ad] %>

O si queremos enlazar directamente a la magazine en lugar de un array pasaremos directamente el objeto padre:

<%= link_to "Magazine details", @magazine %>

Tareas en base de datos

Gestión del plural/singular

Cuando un modelo/recurso tenga un plural irregular, se puede gestionar manualmente por medio de un Inflector. Consultar esta guía.

Relación entre modelos

Estos serían los pasos para establecer una relación 1:n entre dos modelos preexistentes. Se basa en este apartado de las Rails Guides.

Partimos de los modelos Spree::Product de la gem spree_core y el modelo Spree::ProductLayout propio de nuestra aplicación. La relación será un belongs_to de Product a ProductLayout, es decir un n:1. Empezamos añadiendo la relación al modelo Product. Como es una entidad de una gem lo haremos con un fichero decorator:

#app/models/spree/product_decorator.rb
Spree::Product.class_eval do
  belongs_to :product_layout
end

A continuación generamos un migration para añadir el campo que establece la relación en la tabla que mantiene el modelo Product:

$ bundle exec rails g migration AddProductLayoutRelationToProducts

Ahora lo editamos para incorporar el campo:

#db/migrate/20130228153926_add_product_layout_relation_to_products.rb
class AddProductLayoutRelationToProducts < ActiveRecord::Migration
  def change
    change_table :spree_products do |t|
      t.references :product_layout
    end
  end
end

Finalmente ejecutamos el migrate:

$ bundle exec rake db:migrate

Inspeccionar la definición de un método

Si queremos averiguar en qué módulo se encuentra definido un método ejecutamos en consola IRB lo siguiente:

puts Objeto.new.method(:metodo).source_location

o

puts Objeto.instance_method(:metodo).source_location

Sustituyendo “Objeto” y “metodo” por lo que corresponda. Fuente.

Si se trata de un helper partimos de helper, por ejemplo:

helper.method(:tab).source_location

Listar gems instalados

$ gem list --local

Si queremos sólo las versiones de una gem, de rails por ejemplo:

$ gem list --local rails

Generar el API de rails

Para tener en local la versión actualizada del API de rails:

$ rails new dummy_app
$ cd dummy_app
$ bundle exec rake doc:rails

Luego mover el subdirectorio doc/api/index.html a donde nos interese y borrar la dummy_app.

RubyGems Documentation

Para visualizar la documentación de todas las gems instaladas en el sistema ejecutar:

$ gem server

Y abrir la dirección: http://localhost:8808

Problema con el encoding de algunas fuentes en UTF-8

Al incorporar el gem spree_sermepa se produjo el problema descrito aquí.

Hay varias formas de solucionarlo. Una es añadir:

if RUBY_VERSION =~ /1.9/
  Encoding.default_external = Encoding::UTF_8
  Encoding.default_internal = Encoding::UTF_8
end

en la parte superior del Gemfile.

Si se utiliza Passenger para servir la aplicación, otra opción es sustituir la siguiente variable del fichero /etc/apache2/envvars:

export LANG=C

por:

export LANG=es_ES.UTF-8

Downgrade de Rubygems

Tras actualizar a la versión 2.0.3 de Rubygems empecé a tener problemas a la hora de hacer bundle install. Aunque me pedía el password de root luego se producían errores de permisos en los directorios donde se almacenan las gems. La solución fue volver a una versión anterior de Rubygems. En concreto la misma que había en ese momento en el servidor de DinaHosting, es decir la 1.8.23. Se hizo con el siguiente comando:

$ sudo gem update --system 1.8.23

Solución a error “Could not find rake-10.0.4 in any of the sources” con Passenger

En el alojamiento de DinaHosting, al ejecutar por primera vez una aplicación Ruby ejecutada con Passport, se produce el error siguiente:

Could not find rake-10.0.4 in any of the sources

Instalando las gemas en el home del usuario se soluciona el error:

$ bundle install --deployment

Esto instala las gem’s en el directorio vendor/bundle.

Especificar entorno

Para especificar el entorno en una tarea rake añadir al final de la orden RAILS_ENV=<entorno>. Por ejemplo para desarrollo:

$ bundle exec rake routes RAILS_ENV=development

Con el script rails, depende. Si se quiere arrancar la consola añadir al final el entorno sin más. Por ejemplo para desarrollo:

$ bundle exec rails c development

Si se quiere arrancar el servidor Webrick añadir el entorno por medio de la opción -e. Por ejemplo para desarrollo:

$ bundle exec rails s -e development

Desinstalación de todas las gems

Con el siguiente comando:

$ gem list | cut -d" " -f1 | xargs gem uninstall -aIx

Posteriormente habrá que volver a instalar Bundler y el resto de gems. Para ello:

$ sudo gem install bundler
$ cd <proyecto>
$ bundle install

Plurales/Singulares de resources

Recurso de tipo colección dentro de un namespace:

Elemento Plural/Singular Ejemplo
Tabla en base de datos Plural spree_posts
Clase del modelo Singular Spree::Post
Fichero del modelo Singular spree/post.rb
Clase del controlador Plural Spree::PostsController
Fichero del controlador Plural spree/posts_controller.rb
rails generator Singular rails g resource spree/post title:string body:text
Ruta en config/routes.rb Plural resources :posts
Directorio en views Plural spree/posts

Ejecutar una versión concreta de rails

Si tenemos instaladas varias versiones del gem de rails, para forzar que se utilice el script rails de una versión concreta, pondremos la versión de la siguiente forma:

$ rails _3.2.13_ -v

De forma que si por ejemplo queremos generar un nuevo proyecto con la versión 3.2.13 haremos:

$ rails _3.2.13_ new nueva_app

Ejecutar una versión concreta de spree

Si tenemos instaladas varias versiones del gem de spree, para forzar que se utilice el script spree de una versión concreta, pondremos la versión de la siguiente forma:

$ spree _1.3.3_ -v

De forma que si por ejemplo queremos hacer la instalación dentro de una aplicación rails nueva con la versión 1.3.3 de Spree haremos:

$ spree _1.3.3_ install

Diagramas ERD

A continuación se indica el comando para obtener una serie de diagramas ERD interesantes. La documentación de todos los parámetros de ERD está aquí.

Modelado de producto en Spree:

$ bundle exec rake erd attributes=foreign_keys only="Spree::Product,Spree::OptionType,Spree::OptionValue,Spree::Variant,Spree::ProductOptionType" title='Productos'