Instalando Mod_Ruby
Wednesday, 22 April , 2009
Bueno dada la escasa y fea documentación que mod_ruby tiene me decidí a escribir un pequeño tutorial de instalación del mismo en debian, que paso a detallar:
Primero instalamos el modulo de apache para ruby (mod_ruby)
apt-get install libapache2-mod-ruby
Luego debemos crear el siguiente archivo:
vi /etc/apache2/mods-available/ruby.conf
y ponemos lo siguiente:
<IfModule mod_ruby.c> RubyRequire apache/ruby-run <Files *.rbx> SetHandler ruby-object RubyHandler Apache::RubyRun.instance </Files> </IfModule>
Entre otras cosas le decimos que debe tratar los archivos .rbx como
archivos de ruby.
Luego de esto ya tenemos los dos archivos necesarios para habilitar el módulo en apache:
ruby.load (que secopia al instalar el módulo) y ruby.conf generado por nosotros. Ahora cómo mod_ruby ejecuta los scrips de ruby como CGI necesitamos poner la directiva Options +ExecCGI en el folder dónde vamos a poner nuestros scripts, en mi caso particular necesito que todos los usuarios del sistema puedan ejecutar sus scripts desde su ~/public_html entonces para lograr esto tenemos que editar la configuración del módulo user_dir, editamos el archivo
vi /etc/apache2/mods-available/userdir.confy agregamos lo siguiente:<IfModule mod_userdir.c> UserDir public_html UserDir disabled root <Directory /home/*/public_html> AllowOverride FileInfo AuthConfig Limit Indexes Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec # Para poder ejecutar scripts en ruby agregamos la linea de abajo Options +ExecCGI <Limit GET POST OPTIONS> Order allow,deny Allow from all </Limit> <LimitExcept GET POST OPTIONS> Order deny,allow Deny from all </LimitExcept> </Directory> </IfModule>
No sé si esto muy seguro o tiene alguna consecuencia no deseada, si es así comenten!
Bueno ahora sólo necesitamos habilitar el móludo para esto ejecutamos el siguiente comando:
a2enmod ruby
y hacemos un reload del apache
/etc/init.d apache2 reload
despues de esto para probarlo ponemos un archivo en nuestro home
vi /home/gaston/test-ruby.rb
con un simple:
puts "hello world"
vamos al navegador a la siguiente url:
http://aca-va-la-url-de-tuserver/~gaston/test-ruby.rb
y vamos a ver un hermoso “hello world” si todo salió bien.
Bueno, con mod_ruby solo para escribir una página web dinámica vamos a tener que hacer algo cómo esto:
puts “<h1>Mi Título</h1>”
lo cual es muy molesto, para hacer las cosas un póco más lindas y más fácil debemos usar eruby que nos permite ejecutar código ruby dentro de archivos de text (como por ejémplo un arhivo html)
Entonces comencemos por instalar eruby:
apt-get install eruby
y luego tenemos que modificar nuevamente el archivo /etc/apache2/mods-available/ruby.conf de esta manera:
<IfModule mod_ruby.c> RubyRequire apache/ruby-run RubyRequire apache/eruby-run <Files *.rbx> SetHandler ruby-object RubyHandler Apache::RubyRun.instance </Files> <Files *.rhtml> SetHandler ruby-object RubyHandler Apache::ERubyRun.instance </Files> </IfModule>
Y luego debemos agregar la siguiente directiva al archivo de configuración de apache /etc/apache2/apache2.conf
AddType text/html .rhtml
Con esto recargamos el apache y ya podemos escribir nuestros .rhtml
y poner código ruby entre los tags <%= %>
Links útiles:
http://en.wikipedia.org/wiki/ERuby
http://wiki.modruby.net/ja/?InstallGuide
http://modruby.net/
http://ubuntuforums.org/archive/index.php/t-356350.html
http://www.ruby-doc.org/docs/ProgrammingRuby/html/web.html
Nested Forms rails 2.3
Wednesday, 18 February , 2009
En el proyecto en el que estoy actualemente estamos usando Rails 2.3, uno de los motivos de usar rails 2.3 es que nos venía muy bien la nueva feature “Nested Forms”, resultaque estuve dando vueltas con algunos problemas hasta que finalmente los saque funcionando bien.
Les cuento yo tengo un formulario para crear un user, el modelo de user es el siguiente:
class User < ActiveRecord::Base has_one :person, :as => :personable, :dependent => :destroy accepts_nested_attributes_for :person .... end
Es decir que un user tiene datos de contacto a travez de has_one :person (suena raro creo que se podría cambiar por has_one :contact_info, :class_name => “Person”) , y entonces el form era el siguiente:
<% form_for(:user, :url => users_path) do |f| -%> <p><%= label_tag 'login' %><br/> <%= f.text_field :login %></p> <p><%= label_tag 'password' %><br/> <%= f.password_field :password %></p> <p><%= label_tag 'password_confirmation', 'Confirm Password' %><br/> <%= f.password_field :password_confirmation %></p> <% f.fields_for(:person) do |person_fields| %> <p><%= person_fields.label :email %><br/> <%= person_fields.text_field :email %></p> <p><%= person_fields.label :first_name, 'First Name:' %><br/> <%= person_fields.text_field :first_name %></p> <% end %> <p><%= submit_tag 'Create User' %></p> <% end -%>
Resulta que esto no me funcionó y me daba el siguiente error:
ActiveRecord::AssociationTypeMismatch (Person(#-619527948) expected, got HashWithIndifferentAccess(#-607513158)):
El problema puntual era que no generaba bien el form y en vez de generar esto:
<input id="user_person_attributes_first_name" name="user[person_attributes][first_name]" size="30" type="text" />
generaba esto:
<input id="user_person_first_name" name="user[person][first_name]" size="30" type="text" />
Y entonces daba el error por que ActiveRecord (Nested model) genera un método person_attributes= en modelo dónde declaramos el accepts_nested_attributes_for (user en este caso) y por eso el form anterior no funciona como era de esperar.
En el controller tenía lo siguiente:
class UsersController < ApplicationController
def new
@user = User.new(:person => Person.new)
end
def create
@user = User.new(params[:user])
@user.save
end
.....
end
La solución fue modificar el form y hacer así:
<% form_for @user do |f| -%> <p><%= label_tag 'login' %><br/> <%= f.text_field :login %></p> <p><%= label_tag 'password' %><br/> <%= f.password_field :password %></p> <p><%= label_tag 'password_confirmation', 'Confirm Password' %><br/> <%= f.password_field :password_confirmation %></p> <% f.fields_for(:person) do |person_fields| %> <p><%= person_fields.label :email %><br/> <%= person_fields.text_field :email %></p> <p><%= person_fields.label :first_name, 'First Name:' %><br/> <%= person_fields.text_field :first_name %></p> <% end %> <p><%= submit_tag 'Create User' %></p> <% end -%>
cambié el
<% form_for(:user, :url => users_path) do |f| -%>
por
<% form_for @user do |f| -%>
El form para editar un user quedó prácticamente igual y funciona con los attributes de person y todo sin hacer nada del lado del controller. Ahora la pregunta es: Esta bien que nested_forms solamente funcione con la forma?:
<% form_for @user do |f| -%>
Si alguien tiene la respuesta que comente!
Saludos
Tirar el código
Saturday, 14 February , 2009
Estoy leyendo un libro de Smalltalk y la verdad leí una frase que me encantó, así que quería dejar plasmada acá:
“El código escrito es importante, pero mucho más importante es el conocimiento que vamos obteniendo conforme programamos. Si aprendemos día a día, probablemente el código viejo no sea bueno. Tirar código no es malo, lo malo es no aprender a diario.”
How Do You Plan Infrastructure?
Thursday, 12 February , 2009
Sigo con la lectura del libro de Kent Y Martin, ahora quiero compartir on Uds. una parte del capítulo 10 titulada “How Do You Plan Infrastructure?”:
“When you plan in a function-oriented, such as we suggest, the obvious question is how to deal with infrasctuture. Before we can start building functionality we have to put together the distributed object messaging infranstructure components before you deliver any customer functionality.
This style of development is a common feature of the dead and dying projects we’ve seen-and we don’t think it’s a coincidence. Doing infrastructure without customer function leads to following risks:
- You spend a lot of time no delivering things that are valuable to the customer, wich straints the relationship with with customer.
- You try to make the infrastructure cover everything you think you might need, wich leads to an overly complex infrastructure.
Therefore, evolve the infrastructure as you build the functionality. For each iteration, build just enough infrastructure for the stories in that iteration. You won’t build a more complex infrastructure than you need, and the customer is engaged in building the infrastructure because she sees the dependent functionality as it’s evolving.”
Creo no hace falta agregar nada, sólo que estoy totalmente de acuerdo con lo que dice.
Overtime doesn’t help.
Tuesday, 10 February , 2009
Hace poco comencé a leer el libro “Planning Extreme Programming” de Kent Beck y Martin Fowler (dos grosos) leyendo el capítulo 7 hay un párrafo que me gustó mucho y quería compartirlo, paso a detallar:
“Overtime doesn’t help. Although in the very short term it does speed up the team, if you do it for any length of time you will get bitten badly. The big killer is motivation. It’s much better to have a motivated programmer work seven hours than a tired, distracted programmer work ten. Even if the programmers want to work long hours it’s not a good idea. Long hours make people tired, tired people make mistakes, and mistakes take time to fix. We’ve both gone into clients in the morning and spent all day chasing a bug that was put in a ten o’clock the previous night. Particularly with young Silicon Valley teams, where long hours are such an important tribal ritual, we have to work hard to get people not to do overtime. If they really have no life, get them to play computer games in the evening instead. It’s much more productive to have castles mown by trebuchets than it is to slip bugs into complicated software.”
La verdad me encantó esta parte del capítulo, sobre todo por que en este último tiempo me he econtrado con varias personas que valoran el “overtime” por más que ello no favorezca a que el sistema avance, y en lo personal trato de no trabajar fuera de hora o cuando estoy muy cansado.
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
Instalando mod_rails en debian, ahorrando RAM
Tuesday, 09 December , 2008
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},
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.



