Posted by calas
Fri, 25 Apr 2008 10:25:00 GMT
El problema
Ruby on Rails ha sido el boom en los últimos dos o tres años
en cuanto a desarrollo web se refiere. Muchos desarrolladores nos
hemos pasado felices y contentos a desarrollar en Ruby, un
lenguaje de programación hasta ahora casi desconocido y que desde el
lanzamiento de Rails ha empezado tomar tanto protagonismo que ahora
ocupa el noveno lugar en la lista de los lenguajes de programación más utilizados.
La creciente comunidad de programadores en ruby se ha volcado con el
opensource y están saliendo a la luz muchos proyectos interesantes
como JRuby, una implementación completa de Ruby sobre JVM;
Rubinus, otra implementación sobre una VM pero esta vez
sobre C; YARV, otra máquina virtual en C que cuentan es muy
rápida y que será la VM de Ruby 2.0 (ya está incluida en la versión
1.9.0 aunque esta no está lista para producción aun sino que es una
especie de preview la versión 2.0); Merb, un framework de
desarrollo Web inspirado en Rails que cada vez está más interesante;
Camping, un miniframework para la creación de Webs sencillas
y toda una lista enorme de proyectos.
Uno de los problemas que encontraban muchos desarrolladores de PHP era
la dificultad para hacer el deploy de aplicaciones Rails en los
shared-hostings. Hasta ahora no había una manera fácil de hacer un
deploy con Apache, o se recurría a fastcgi que es la solución en los
hostings compartidos como Dreamhost o se contrataba un
VPS o servidor dedicado donde un Apache,
Lighthttpd o Nginx hacían de proxy y balanceador entre los
servidores mongrel, thin o lo que fuera de las
aplicaciones rails.
La solución
Y por qué hablo en pasado si hasta día de hoy sigue siendo la forma de
hacer deploy? Este mismo blog está servido por un nginx que hace de
proxy a 2 mongrels.
Es que el pasado 11 de Abril se anunció Phusion Passenger
(aka mod_rails) que promete que hacer un deploy sobre
apache sea extremadamente sencillo, solo cuestión de
subir los ficheros sin hacer nada de configuración especifica de
Rails, mongrel u otro servidor.
La instalación
Anoche me he puesto a probarlo y he quedado impresionado. Al punto de
que toda la instalación, incluida la de apache, me tomó solo unos 10 o
15 minutos.
No es mi objetivo contarles como instalar Rails,
Apache 2 o ruby, sobre eso hay muchas
cosas escritas y pueden buscar en google. O pedírmelo en un comentario
y ya haré otro post.
Así que descontando todo eso la cosa se reduce a:
1- Instalar Phusion Passenger:
sudo gem install passenger
2- Compilar, instalar y configurar el módulo de apache:
sudo passenger-install-apache2-module
Este comando les indicará si les falta alguna dependencia y si todo
va bien les mostrará 3 lineas al final que tienen que incluir en su
configuración de Apache, en mi caso fueron:
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-1.0.1/ext/apache2/mod_passenger.so
RailsSpawnServer /usr/lib/ruby/gems/1.8/gems/passenger-1.0.1/bin/passenger-spawn-server
RailsRuby /usr/bin/ruby1.8
Pero no siempre son iguales, así que no vale hacer copy & paste
3- Configurar un virtual host para tu aplicación.
En la configuración de apache incluir un virtual host
para la aplicación de Rails donde indiques el directorio donde esta
reside:
<VirtualHost *>
ServerName myrailsapp.com
DocumentRoot /home/sites/myrailsapp/public
</VirtualHost>
4- El robocop:
Abrir el navegador e ir http://myrailsapp.com (o la url de tu sitio si
quieres funcione ;)) ya debería estar funcionando. El environment que
se carga por defecto es el de producción, pero hay varias opciones de
configuración que puedes ver en la guía de usuario de passenger
Todavía tengo que hacer muchas pruebas para pasar mis aplicaciones de
la combinación nginx+mongrel_cluster a mod_rails aunque los
benchmarks muestran excelentes resultados habría que
valorar variables como consumo de recursos, etc. Nginx consume menos
recursos que apache pero los mongrels son muy hambrientos y terminan
consumiendo mucho. Otro tema a valorar es la robustez pero ya eso
serían temas para otros posts.
El futuro.
Mirando el panorama el futuro de Rails y los demás frameworks basados
en Ruby parece prometedor. Uno de los beta testers de passenger fue
Dallas de Dreamhost, por lo que cabe esperar que dentro de poco sus
planes de hosting incluyan mod_rails.
El problema seguiría siendo los pocos recursos disponibles en un
ambiente de alojamiento compartido pero los chicos de
Engine Yard están haciendo un esfuerzo importante en
Rubinius, Sun en JRuby y Ruby 2.0 saldrá con YARV incorporado. Todos
estos proyectos mejoran muchísimo el rendimiento actual de Ruby,
corrigiendo muchos errores de implementación de las versiones
actuales. Los chicos de Phussion prometen un consumo de 33% menos de
memoria usando mod_rails con Ruby Enterprise Edition, aunque todavía
no está disponible.
Creo que pronto veremos a los shared hosting tradicionales ofreciendo
un buen soporte para aplicaciones en Ruby on Rails y el mundo será un
mejor lugar, al menos para los programadores de webs. Creo que así
volvería a activar mi cuenta en Dreamhost.
Actualmente Phussion Passenger solo soporta aplicaciones en Ruby on
Rails, al fin y al cabo es mod_rails y no mod_ruby, pero al ser un
proyecto opensource puedo apostar a que dentro de muy poco tiempo la
comunidad habrá aportado soporte para Camping, Merb, Nitro o cualquier
otro framework.
Posted in Ruby on Rails | Tags apache, deploy, rails, ruby | no comments
Posted by joahking
Thu, 24 Apr 2008 09:51:00 GMT
Ajax ha sido un boom en el desarrollo web en los últimos tiempos, es un hecho.
Pero no es una alfombra mágica, y mal usado puede crear problemas de rendimiento. Puedes probar una busqueda en
Google, pero los puntos problematicos son estos más o menos:
Por ejemplo, los Cascade Selects que me han regalado en Navidad mejorarían el rendimiento si mandara a la vista todos los datos necesarios y construir los selects usando OPTGROUP y no pedir pequeñas cantidades por Ajax cada vez que elijo Galicia en vez de Murcia.
Esto es precisamente lo que intenta resolver el nunca suficientemente alabado Ryan Bates en su railscast
Dynamic Select Menus. Su idea es en la vista pedirle js a un javascript controller:
<!-- views/somethings/new.html.erb -->
<% javascript 'esta_accion' %>
# application_helper.rb
def javascript(*files)
content_for(:head) { javascript_include_tag(*files) }
end
# y en el javascript_controller
def esta_accion
@datos = Dato.find :all
end
Luego el erb parseará el views/javascripts/esta_accion.js.erb que se encargará de generarnos un javascript a la medida.
Hasta aquí todo bien, pero si lo miramos con el tipo de ojo correcto esto no nos resuelve el problema completamente. Mirando los logs notamos que para generar la vista new de los somethings estamos haciéndole dos peticiones al Rails.
Fíjate que este dos es una palabra maleta: no solo lleva dentro otra petición Rails (¡petición es otra palabra maleta!), sino y esto es peor: si el proceso es más complejo que mis simples selects estaré repitiendo código del negocio de la acción new de Something en otro controller (oh Dios! dira el Pana, unDRY code! y saldrá corriendo a desinfectarse las manos).
O sea que eliminamos los muchos accesos al DOM y el Ajax pero a muy mal precio, ¿porqué no reducimos el round-trip a solo una request?
¡Que entre Unobstrusive Javascript !
no voy a extenderme diciendo qué es el Javascript No Obstrusivo, para eso están los gurus y Mr. Google.
Resumiendo la idea es sacar el javascript del html y pegarle eventos a los elementos desde un javascript después que la página esté cargada:
<!-- algún html define el elemento -->
<button id="alertable">Click me!</button>
<!-- algún javascript le pega el evento onclick -->
document.observe(
"dom:ready",
function() {
document.getElementById("alertable").addEventListener( 'click',
function() {
alert("Gracias, he esperado toda mi vida este momento!");
},
false);
});
Hay un screencast muy bueno en
railsenvy sobre cómo integrar
UJS en Rails. Quedaría así resumiendo:
<!-- en el layout -->
<head>
<%= yield :unobstrusive_javascript %>
</head>
<!-- views/algos/show.html.erb -->
<% content_for :unobtrusive_javascript do -%>
<script type="text/javascript" charset="utf-8">
document.observe(
"dom:ready",
arrancaUserInterface('<%= @datos_para_la_UI.to_json %>'),
false
);
</script>
<% end %>
Wow! Gracias Jason, ya no necesitamos más el javascripts_controller, estoy contento con esta solución pero igual me falta la elegancia de la solución anterior, donde no tenía javascript en el head de mi html, sino en un hermoso esta_accion.js.
Talvez UJS4Rails es lo que estoy buscando, pero…
Si este fuera el mejor de los mundos posibles ¿cómo querría que esto quedara?
Me gustaría que en el procesamiento MVC de la petición Rails transformara la V en V + js, así tendriamos unobstrusive js out of the box, REST y algunas otras golosinas. Pero quien sabe si Rails Edge….
Posted in Ruby on Rails | Tags ajax, javascript, performance, rails, unobstrusive | no comments
Posted by The Turing Machine
Sun, 28 Oct 2007 15:31:00 GMT
Esta es una guía de referencia para instalar y configurar el Radiant CMS, a medida que vaya desarrollando el proyecto que estoy realizando, iré posteando los problemas y soluciones que encuentre en el camino.
Sin más rodeos, vamos a lo que nos interesa. Para instalar el radiant ejecutamos
gem install radiant -y
Para crear un nuevo proyecto, hacemos:
% radiant --database [mysql|postresql|sqlite3] ruta/del/proyecto
Ahora, configuramos el fichero config/database.yml de acuerdo a nuestra configuración. Una vez creada la base de datos. Ejecutamos
% rake [environment] db:bootstrap
Si queremos iniciar en desarrollo, omitimos el parametro environment, de lo contrario pasamos el nombre del environment, test o production.
Cuando nos lo solicite, le diremos que vamos a usar el template de blog estilizado, esto para tener unos ficheros básicos de estilo, y algunas páginas por defecto, las cuales nos servirán de guía, y que luego reemplazaremos por nuestras propias páginas. De cualquier forma tienes la opción de usar el template vacío y empezar todo desde cero.
Luego, ejecutamos nuestro servidor para ver que esté todo funcionando.
% script/server -e production
Accesamos nuestro servidor, y ya podemos empezar a usar el radiant.
Para utilizar el radiant, sugiero leer el siguiente tutorial: Art of Mission Radiant CMS
Instalando Extensiones
Para encontrar información sobre las extensiones disponibles, podemos entrar en http://dev.radiantcms.org/radiant/wiki/Extensions
Seguramente, en nuestra páginas, vamos a querer tener attachments, como ficheros o imágenes, por lo que primeramente vamos a instalar la extensión Page Attachments. Para esto hacemos:
% cd ruta/del/proyecto
% svn checkout http://svn.seancribbs.com/svn/rails/plugins/extensions/page_attachments vendor/extensions/page_attachments
Luego, realizamos las migraciones necesarias en nuestro environment, e inicializamos:
rake db:migrate:extensions
rake radiant:extensions:page_attachments:update
Reiniciamos el servidor.
En este momento, ya podemos subir ficheros a nuestras páginas. La extensión de Page Attachments, nos permite crear miniaturas (thumbnails) de las imágenes que cargamos. Para esto, debemos tener instalado ImageScience, RMagick o MiniMagick.
Lo primero es instalar ImageMagick. podemos obtenerlo de esta página. Después de instalarlo, tuve ciertos problemas para crear los thumbnails con algunos formatos de imágenes. Para saber que formatos podemos utilizar ejecutamos
% identify -list format
Si alguno de los que nos interesa no está en la lista, tendremos que configurar el ImageMagick, pero ese es tema para otro post.
Luego tenemos que instalar el Mini Magick para esto ejecutamos:
% gem install mini_magick
Ahora editamos el fichero /vendor/extensions/page_attachments/app/models/page_attachment.rb tal que tengamos algo similar a esto:
has_attachment :storage => :file_system,
:thumbnails => { :thumb => '50x50!' },
:resize_to => '400x300',
:processor => :mini_magick,
:max_size => 10.megabytes
:resize_to, convierte las imágenes automáticamente, si lo omitimos no hace nada.
:thumbnails => { :thumb => ‘50×50!’ }, aquí podemos indicar los distintos tamaños que queremos para las miniaturas.
:processor, nombre del procesador de imagenes.
Para más información sobre estas opciones, debemos leer sobre el plugin attachment_fu, aquí una buena referencia, aunque sólo en inglés.
Guardamos los cambios en el fichero, y reiniciamos. Ya podremos crear thumbnails de nuestras imágenes y llamarlas usando las etiquetas r:attachment.
Pronto publicaré más información de cosas que vaya necesitando en Radiant.
Posted in Ruby on Rails | Tags radiant_cms, tutorial | 1 comment
Posted by calas
Sun, 21 Oct 2007 07:20:00 GMT
Emacs + Rails es una buena combinación para trabajar con Ruby on Rails utilizando Open Source y en cualquier plataforma. Al final todo el equipo lo está utilizando y pasamos por el momento de comprar una macbook y Textmate. Emacs es muy potente y totalmente configurable. Quizás deberíamos hacer un post sobre este tema porque este no va de eso. Sino de un pequeño tip cuando ya lo estás utilizando.
Problema
Resulta que el emacs-rails tiene una combinación de teclas muy útiles cuando estás programando y me refiero a M-S up con la cual podremos movernos fácilmente entre un método del controlador y su correspondiente vista, y viceversa.
El problema con esta combinación es que no tiene definidos todos los tipos de archivo en los que puede estar contenida una vista.
Yo por ejemplo estoy utilizando el plugin Rtex de Bruce Williams y tengo una vista que se llama etiquetas.rtex, en el controlador de impresiones tengo un método que se llama etiquetas, pero no puedo moverme fácilmente entre ambos búferes, abrirlos o crear las vistas.
Solución
Después de mirar un poquito el rails.el dentro de emacs-rails encontré la variable que contiene la lista de extensiones de archivo válidas para las plantillas erb: rails-template-list.
En el fichero ~/.emacs añadí las lineas:
(add-to-list 'rails-templates-list "rtex")
(add-to-list 'auto-mode-alist '("\\.rtex$" . tex-mode))
Y problema resuelto.
El fichero se abre con el modo mayor tex-mode así que añadí estas lineas para que también tuviera Ruby mode utilizando mmm-mode
(add-hook 'tex-mode-hook
(lambda ()
(setq mmm-classes '(erb-code))
(mmm-mode-on)))
Nota: Se asume que ya tienes emacs-rails, mmm-mode, ruby-mode, etc… Todo bien instalado y configurado.
Referencias
Manual de referencia de Elisp (En Inglés)
Emacs on Rails (En Inglés)
Posted in Ruby on Rails | Tags elisp, emacs, rails, rtex, trucos | no comments
Posted by joahking
Mon, 15 Oct 2007 02:34:00 GMT
¿Has intentado definir en una asociación que se detenga el borrado del objeto si existen otros que lo refieran? Por ejemplo: Padre, tiene Hijos y Nietos, y no quieres que sea destruido si tiene algún hijo o nieto. La asociación has_many de Rails provee tres opciones para mantener la integridad de datos con :dependent => {:destroy | :delete_all | nullify}. Pero pasa por alto este caso tan común.
Por suerte Rails brinda posibilidades aun en el caso de que algo falte, y esta es una buena oportunidad para un plugin y usar un poco de metaprogramación. El plugin stop_deletion_if_has_children resuelve esto de manera sencilla:
La declaración de la restricción en el modelo es así:
# padre.rb
has many :hijos
has_many :nietos
stop_deletion_if_has_children :hijo, :nieto
(Nótese que el singular es importante en la declaración de cada parámetro pasado al plugin, según la implementación dada.)
# init.rb
require 'stop_deletion_if_has_children'
ActiveRecord::Base.send(:extend,Qvitta::StopDeletionIfHasChildren)
El plugin recorrerá la lista de objetos enlazados pasados como parámetros y chequeará que no existan records en el momento de destruir el objeto.
Esto es lo que hace:
# stop_deletion_if_has_children.rb
module Qvitta #:nodoc:
module StopDeletionIfHasChildren #:nodoc:
def stop_deletion_if_has_children(*children)
define_method "children_check" do
ret = true
for child in children do
if self.send("#{child}".to_s.pluralize).length > 0
self.errors.add_to_base "Error: #{self.class} contiene #{child.to_s.camelize.pluralize}"
ret = false
end
end
return ret
end
before_destroy :children_check
end
end
end
Las claves en el código anterior son:
*children: el asterisco le dice a Rails que el parámetro del método es un arreglo de valores.
before_destroy :children_check: que interpone el método children_check justo antes de la destrucción del objeto, y permite la destrucción return true o la detiene return false (se devuelven todos los mensajes de errores posibles en una sola pasada).
La metaprogramación viene dada por las lineas:
define_method "children_check" do: define al vuelo el método children_check.
Si como yo, tienes modelos con nombres en español la linea corta:
if self.send("#{child}".to_s.pluralize).length > 0
puede fallar pues pluralize lo hará en ingles. En ese caso necesitas hacer el chequeo desde los descendientes hacia el padre con esta más larga:
if "#{child}".to_s.camelize.constantize.send("find_all_by_#{self.class.to_s.downcase}_id",self.id).length > 0
Esta linea más larga nos da el pie didáctico para más de metaprogramación:
- camelize: para convertir la cadena ‘hijo’ en ‘Hijo’.
- contantize: que convierte la cadena ‘Hijo’ en la clase Hijo.
- send: que invoca el método pasado como parámetro en la clase obtenida con el tratamiento anterior (en nuestro caso: Hijo.find_all_by_padre_id).
Pues eso es. A ver si con un poco de suerte (y tiempo) ponemos el repositorio de plugins de Qvitta accesible esta semana, y asi se podrá descargar.
Posted in Ruby on Rails | Tags integrity, metaprogramación, plugin, rails, referencial | no comments
Posted by calas
Wed, 10 Oct 2007 08:30:00 GMT
Se me ha ocurrido la idea de ir posteando mis helpers a medida que los haga (siempre que sean útiles y reutilizables). Así que hoy va el primero, muy sencillo para ir poniendo en las vistas lo que me falta por hacer, por ejemplo en la vista pongo:
<%= todo "Pasar el todo el estilo a un CSS" %>
El código en application_helper.rb la verdad que es una tontería:
def todo(msg)
"<strong>TODO: </strong>#{msg}<br />"
end
Simple verdad?
Se podría mejorar añadiendole clases y estilos (en linea; no en una hoja de estilos a no ser que sea una de pruebas que no va a pasar a producción, al fin y al cabo no debe quedar ninguna etiqueta de estas en una aplicación en producción)
ACTUALIZACIÓN:
Un pequeño cambio de estilo:
def todo(msg)
"<p style='color: red'><strong>TODO: </strong>#{msg}</p>"
end
El resultado:
TODO: Pasar el todo el estilo a un CSS
De esta manera tengo mis vistas con muchos recordatorios de las cosas que me faltan por hacer.
Posted in Ruby on Rails | Tags helpers, rails, ruby, trucos | no comments