Red de blogs de la NFL en Rails muy pronto!

Tuesday, 03 February , 2009

Hace mucho que no escribía un post, esta vez es para comunicarles que han instalado una red de más de 30 blogs de la NFL con el sistema de blog desarrollado por mí completamente en Rails, los blogs aún no fueron lanzados oficialmente (esto será en breve). Además del sistema de blog a medida hice un script para facilitar la instalación, para que una persona con pocos concimientos pueda setear un nuevo site completo (esto incluye el virtal server, base de datos, etc). Realmente quería postear esto por que me parece un buen ejemplo para mostrar lo productivo que es Ruby y Ruby on Rails, les cuento algunos números. El sistema de blog fue desarrollado aproximadamente en 5 meses contando la instalación completa del servidor, me parece un muy buen tiempo teniendo en cuenta que había único desarrollador dedicado a full a este proyecto. En un principio se hizo el blog para el equipo de la NFL Giants (http://www.bigbluepass.com/) luego estuve un mes escribiendo el script para automatizar la instalación y haciendo que el blog sea “genérico” es decir se pueda utilizar para cualquier equipo y tener la posibilidad de configurarlo por completo (colores, imágenes, título, css, etc.).
Vamos a lo que nos interesa:

El sistema: Un sisema de blog a medida para fanáticos de equipos de la NFL
Plugins Utilizados:

acts_as_state_machine
acts_as_taggable_on_steroids
attachment_fu
colorpicker
dnsbl_check
easy-fckeditor
meteor_strike
permalink_fu
recaptcha
restful_authentication
rspec
rspec-rails
selenium-on-rails
timed_fragment_cache
will_paginate

Rake stats:

+----------------------+-------+-------+---------+---------+-----+-------+
| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Controllers          |  1142 |   824 |      21 |     137 |   6 |     4 |
| Helpers              |   452 |   325 |       0 |      46 |   0 |     5 |
| Models               |   767 |   508 |      18 |      64 |   3 |     5 |
| Libraries            |   370 |   230 |       2 |      45 |  22 |     3 |
| Model specs          |   668 |   519 |       0 |      10 |   0 |    49 |
| View specs           |   200 |   142 |       0 |      10 |   0 |    12 |
| Controller specs     |  1671 |  1272 |       0 |      41 |   0 |    29 |
| Helper specs         |   191 |   169 |       0 |       2 |   0 |    82 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total                |  5461 |  3989 |      41 |     355 |   8 |     9 |
+----------------------+-------+-------+---------+---------+-----+-------+
  Code LOC: 1887     Test LOC: 2102     Code to Test Ratio: 1:1.1

rake spec:models: 79 examples, 0 failures

rake spec:controllers: 180 examples, 0 failures

El instalador: Un script para automatizar y facilitar la instalación de los blogs (Ruby + Mod_Rails)

Ambiente de producción:Apache + Mod_Rails + Ruby Enterprise Edition

Desarrolladores: 1 (yo hice casi todo menos los css, algunas cosas en javascript y el módulo que muestra los slides en la portada que lo hizo César Díaz )

Cómo autocrítica puedo decir que me hubiera gustado que tenga más cobertura de tests, pero bueno será para la próxima.

Esta es la red de blogs:

http://www.atlrumble.com
http://www.baltimoreregister.com
http://www.bigbluepass.com
http://www.bigeasyfootball.com
http://www.bluestardaily.com
http://www.boltsnotes.com
http://www.bucreport.com
http://www.buffaloregister.com
http://www.carolinarules.com
http://www.catspass.com
http://www.cincyrecord.com
http://www.dawgpoundlive.com
http:/www.fanpublic.com
http://www.ganggreenwire.com
http://www.greenbayreport.com
http://www.greennationreport.com
http://www.hawkscountry.com
http://www.kclocker.com
http://www.milehightimes.com
http://www.motorcitypress.com
http://www.musiccitywire.com
http://www.ninerpride.com
http://www.oaklandnotes.com
http://www.phinpass.com
http://www.redbirdcrew.com
http://www.skinsreport.com
http://www.steelcurtaintimes.com
http://www.stlouisnotes.com
http://www.texalley.com
http://www.truebluegang.com
http://www.vikespeak.com
http://www.wickedpats.com
http://www.windycitynation.com

Esto fue todo, hasta el póximo post ;)

Hace un tiempo que me enteré que existe mod_rails y que tengo ganas de implementarlo en mi vps (dónde está alojado el sitio de rubylit entre otros) El vps tiene 300 MB de RAM en total, y hasta ahora tenía nada más que 30MB libres ( cada instancia de mongrel me consumia unos 40MB aprox.)

Así que aquí vamos con la instalación de mod_rails.

Primero vamos a instalar Ruby Enterprise Edition cómo recomiendan los chicos de passenger (mod_rails), también podemos usar el ruby convencional.

Para esto nos bajamos el .tar.gz con los sources y lo descomprimimos:

wget -c http://rubyforge.org/frs/download.php/47937/ruby-enterprise-1.8.6-20081205.tar.gz
tar -xvvzf ruby-enterprise-1.8.6-20080810.tar.gz

Yo lo voy a instalar en /opt que es dónde se instalan los paquetes que no vienen con la distro entonces quedaría:

/opt/ruby-enterprise-1.8.6-20080810/

Instalamos las libs necesarias para compilar ruby EE:

apt-get install g++ zlib1g-dev libssl-dev build-essential

Al intentar instalarlo me tiró el siguiente error, pero leyendo algunos mails de la lista de Ruby EE recomendaban ejecutar el instalador de la siguiente manera:

cd /opt/ruby-enterprise-1.8.6-20080810/
./installer --no-tcmalloc

y funcionó…

Ahora tenemos que crear una serie de links simbólicos para que nos quede la versión de Ruby EE instalada correctamente:

ln -fs /opt/ruby-enterprise-1.8.6-20080810/ /opt/ruby-enterprise
ln -fs /opt/ruby-enterprise/bin/gem /usr/bin/gem
ln -fs /opt/ruby-enterprise/bin/irb /usr/bin/irb
ln -fs /opt/ruby-enterprise/bin/rake /usr/bin/rake
ln -fs /opt/ruby-enterprise/bin/rails /usr/bin/rails
ln -fs /opt/ruby-enterprise/bin/ruby /usr/bin/ruby
ln -fs /opt/ruby-enterprise/lib/ruby/ /usr/lib/ruby

Ahora instalamos la gema de mysql

apt-get install libmysqlclient15-dev

/opt/ruby-enterprise-1.8.6-20080810/bin/ruby /opt/ruby-enterprise-1.8.6-20080810/bin/gem install mysql

Ya tenemos instalado Ruby EE entonces ahora vamos a instalar mod_rails.

bajamos los sources de passenger:

wget -c http://rubyforge.org/frs/download.php/47928/passenger-2.0.5.tar.gz
tar -xvvzf passenger-2.0.5.tar.gz

Instalamos las lib necesarias para compilar:

apt-get install ruby-dev libopenssl-ruby rubygems  apache2-prefork-dev build-essential

Instalamos apache prefork:

apt-get install apache2-mpm-prefork

Ahora tenemos que instalar mod_rails:

cd /opt/passenger-2.0.5
./bin/passenger-install-apache2-module

luego editamos el archivo /etc/apache2/mods-available/passenger.conf
y ponemos lo soguiente:

PassengerRoot /opt/passenger-2.0.5
PassengerRuby /opt/ruby-enterprise-1.8.6-20080810/bin/ruby

editamos el archivo /etc/apache2/mods-available/passenger.load
y ponemos lo siguiente:

LoadModule passenger_module /opt/passenger-2.0.5/ext/apache2/mod_passenger.so

luego tenemos que activar el modulo entonces ejecutamos el siguiente comando:

a2enmod passenger

Listo ahora lo único que tenemos que hacer cada vez que agregamos una app
es agregar un virtual host en apache.
Editamos el archivo /etc/apache2/sites-available/nueva_app.com
y ponemos lo siguiente:

    <VirtualHost *:80>
    ServerName www.nueva_app.com
    ServerAlias nueva_app.com
    DocumentRoot /var/www/apps/nueva_app.com/public
    RailsBaseURI /
    CustomLog /var/log/apache2/nueva_app.com.log "%h %l %u %t \"%r\" %>s %b"
   </VirtualHost>

Como pueden ver puse el archivo de log separado del lo general de apache.
luego de esto habilitamos el nuevo virtual host

a2ensite nueva_app.com

y reiniciamos apache:

/etc/init.d/apache2 reload

y listo.

Ahora en mi vps tengo 165MB de RAM libres, así que la migración fue productiva, cabe destacar que tuve que migrar de nginx a apache entonces todos los virtual hosts (státicos y dinámicos) que tenía creados en nginx los tuve que migrar a apache, pero no fue algo complicado.

Aguante named_scope !

Tuesday, 14 October , 2008

Hace un tiempito que vengo usando named_sope en mis modelos y la verdad que cada vez me sorprendo más, en esta ocasión me hice uno que utilizo con el plugin acts_as_taggable_on_steroids, que retorna los posts que poseen cierto tag:


#############################################################
# Scopes

 named_scope :tagged_with, lambda{|tags|
    conditions =   {:conditions => { :published => true},
                    :o rder => 'created_at DESC',
                    :match_all => true}
    find_options_for_find_tagged_with(tags, conditions)
  }

Además acá les dejo los specs que escribí para este scope:


describe Post, "tagged_with" do
  fixtures :posts

  before(:each) do
    @tag = "ruby"

    1.upto(4) {
      p = create_post
      p.tag_list << @tag
      p.published = true
      p.save
    }
  end

  it "should have all tagged with #{@tag}" do
    Post.tagged_with(@tag).each{ |p| p.tag_list.should include(@tag) }
  end

  it "should have at least 3 posts tagged with #{@tag}" do
    Post.tagged_with(@tag).should have_at_least(3).posts
  end

end

Los specs no me convencen mucho así que si alguien tiene alguna forma mejor de hacer que me avise.

Todos festejamos nuestro día…

Friday, 12 September , 2008

Fryda...

Fryda...

Felíz día del programador!

Friday, 12 September , 2008


Hoy es el día número 256 del año, día elegido como el día del programador, saludos para todos los que soportamos las presiones de los deadlines y demás.

Muchas veces cuando tenemos recursos anidados nos encontramos definiendo un map.resource (o una ruta) adicional para acceder al mismo recurso pero sin la anidación. Para referenciar a un miembro específico de este sin el prefijo del padre sin tener que definir otra ruta, Rails edge agrega una opción a map.resource para lograr esto.

Ejemplo:

map.resources :users, :shallow => true do |user|
  user.resources :posts
end

* GET /users/1/posts (mapea a la acción PostsController#index action como siempre)
se agrega la ruta nombrada “user_posts” como siempre.

Lo nuevo:

* GET /posts/2 (mapea a la acción PostsController#show como si no sería anidada)
Adicionalmente, se agrega también la ruta nombrada “post”.

Tengo el agrado de de comunicarles que junto con Lucas Florio hemos finalizado la traducción completa al español del libro “Rails 2.1 ¿Qué hay de nuevo?” de Carlos Brando, la pueden descargar desde aquí y también está disponible la versión en html, este es el proyecto en github. Desde ya cualquier sugerencia o corrección es bienvenida.

Descargar el libro: http://gastonramos.com.ar/rails21/rails21-que-hay-de-nuevo.pdf

Como inicializar un repositorio git

Thursday, 28 August , 2008

Hace mucho que no escribía, en este caso el tema es como inicializar un repositorio en git, básicamente consta de 2 partes una del lado del servidor y otra en el cliente.

Paso 1: vamos al server y corremos el siguiente script:

./init-repo-server-side.sh proyecto-nuevo

el script va a crear un nuevo repositorio git en /srv/git/proyecto-nuevo.git
con permisos para el user git que vamos a tener que agregar
al server, este usuario sólamente tiene que tener permisos para correr el comando git y nada más.

Script para correr en el server:


#!/bin/sh -x
# init-repo-server-side.sh
PROJECT=$1

REPO=/srv/git/$PROJECT.git

echo Creando $REPO ...

mkdir -p $REPO
cd $REPO
git --bare init
chown -R git:git $REPO
chmod g+w $REPO -R
chmod a+x hooks/post-update
touch git-daemon-export-ok

Paso 2: Luego vamos a la máquina cliente y ejecutamos el siguiente script:

./init-git.sh proyecto-nuevo

Este nos va a crear una carpeta proyecto-nuevo.git que va a contener
una copia de nuestro proyecto, que ya podemos comenzar a utilizar.

Script para correr en el cliente:


#!/bin/sh -x
#./init-git.sh
PROJECT=$1.git

URL=ssh://git@nuestro-server.com/srv/git/$PROJECT

echo Creando $PROJECT

mkdir $PROJECT
cd $PROJECT

git init
touch .gitignore
git add .gitignore
git commit -m "just gitignore"
git remote add origin $URL
git config branch.master.remote origin
git config branch.master.merge refs/heads/master
git push --all
git pull

Esto fue todo, espero que les sea útil.

Acts as date Module

Thursday, 26 June , 2008

Esta es una solución que se me ocurrió para hacerme más cómodo el trabajo con
el atributo created_at de un modelo, por ej:

Para saber el año de creación de un post, haríamos lo siguiente:

>> p = Post.find(1)
>> p.created_at.month
=> 6

como podemos observar retorna 6, pero resulta que yo lo necesito necesito con el siguiente formato: “06″. Lo mismo pasa con el día:

>> p = Post.find(1)
>> p.created_at.day
=> 4
module ActsAsDate

  def year
    created_at.strftime("%Y")
  end

  def month
    created_at.strftime("%m")
  end

  def day
    created_at.strftime("%d")
  end

  def year_month
    [year, month]
  end

  # Armo un string para usarlo en un find
  #    ej:
  #   params = {:year => "2008", :month => "06"}
  #   Post.all(:conditions => Post.created_at_conditions(params))
  #
  def self.included(klass)
    klass.class_eval do
      def self.created_at_conditions(params)
        return nil if params[:year].blank? or params[:month].blank?
        "created_at like '#{params[:year]}-#{params[:month]}%'"
      end
    end
  end

end

Entonces tenemos que incluir este módulo en modelo que lo queremos usar:

class Post < ActiveRecord::Base

  include ActsAsDate

end

Ahora con esto directamente hago p.month, p.day, p.year y obtengo el mes, día y año de creación del post con el formato que necesito y escribiendo menos código :) . Además agregué un método que me arma el param conditions, que se podría un usar así por ej:


class PostsController < ApplicationController

def list
    @posts = Post.paginate(
         :page => params[:page],
         :o rder => 'created_at DESC',
         :conditions => Post.created_at_conditions(params)
    )

    respond_to do |format|
      format.html
      format.xml  { render :x ml => @posts }
    end
  end

end

De esta manera no tengo que estar preguntando en el controller si vienen (year y month) como parámetros, por ahora este modulo sólo funciona con el atributo created_at por que está hardcodeado, pero con pocas modificaciones se podría hacer que funciona para cualquier atributo.
Ahora lo que me pregunto es si Rails ya tiene alguna solución mejor para este problema, si alguien la conoce que me lo haga saber por favor (yo no la encontré), además se aceptan modificaciones, sugerencias y comentarios.

Información de debug en Rails

Thursday, 26 June , 2008

Muchas veces cuando estamos desarrollando una aplicación web necesitamos mirar cierta información de debug, acá les dejo una mi versión de este senippet que leí por acá .

La idea es poner este código en un partial:

 app/view/views/shared/_debug_info.html.erb

y luego ponemos el render en el layout de la aplicación:

 <%= render :partial => 'shared/debug_info' %>

Va el pastie: http://pastie.org/222621