En un post anterior les comente sobre gedit, un excelente editor y potencialmente un gran IDE. Hace unos días atrás volví a usarlo para unos experimentos en Ruby on Rails. Pero había archivos en los que no funcionaba bien el resaltado de código (hight light code). Principalmente en los archivos de vistas ERB. Buscando encontré estos highlightcodes y aquí les cuento como instalarlos en Linux.
1] Busquen sus propios highlightcodes. Aquí hay algunos para: haml, sass, erb y otros archivos que generalmente encontramos en un proyecto rails.
2] Copiar los archivos mime y lang-specs a sus correspondientes directorios:

sudo cp ./mime/* /usr/share/mime/packages/
sudo cp ./lang-specs/* /usr/share/gtksourceview-2.0/language-specs/

3] Agregar los mime types a la base de datos:

sudo update-mime-database /usr/share/mime

y listo!

Créditos
Los syntax hightlight los extraje de aquí
Las instrucciones de como instalarlos desde aquí

Post to Twitter Tweet This Post

, , , , ,

Active record es un patrón de diseño. Es un enfoque al problema de acceder a los datos de una base de datos. Donde cada tabla es una clase por lo que cada fila es asociada con objetos del lenguaje de programación usado. Cuando se crea uno de estos objetos, se añade una fila a la tabla de la base de datos. Cuando se modifican los atributos del objeto, se actualiza la fila de la base de datos.[1]

1.- Usos super básicos[2]

# == Schema Information
# Schema version: 20100829195102
#
# Table name: users
#
#  id         :integer(4)      not null, primary key
#  first_name :string(255)
#  last_name  :string(255)
#  email      :string(255)
#
 
class User < ActiveRecord::Base
  has_many :posts
end
 
# == Schema Information
# Schema version: 20100829195102
#
# Table name: posts
#
#  id         :integer(4)      not null, primary key
#  title      :string(255)
#  body       :text
#  state      :string(255)
#  user_id    :integer(4)
#  created_at :datetime
#  updated_at :datetime
#
 
class Post < ActiveRecord::Base
  belongs_to :user
end

Agregando datos:
1.1) Atributo por atributo

u = User.new
u.first_name = "Marcos"
u.last_name = "Vanetta"
u.email = "marcos@correo.com"
u.save

1.2) Pasando todos los atributos con un diccionario

u2 = User.create :first_name => "John", :last_name => "Doe", :email => "johndoe@correo.com"

nota: Aquí no es necesario el save

1.3) Actualizando un atributo en particular:

u.update_attribute :email, "johndoe@gmail.com"

Nota: Este procedimiento no incurre en validaciones, vea también [3]

1.4) Actualizando con un diccionario:

u = User.first
u.update_attributes :first_name => "Dexter", :last_name => "Morgan", :email => "dexter@morgan.com"

nota: update_attributes! Es igual al anterior, pero sin validaciones.

1.5) Eliminar un registro:

u = User.last
u.destroy

Búsquedas simples
2.1) Obtener todos los registros:

users = User.find(:all)
users = User.all # => Alias para el anterior

nota: Nunca recomendable. Si hay una gran cantidad de registros se puede dar un gran consumo de memoria.

users = User.all :limit => 10, :offset => 0
# Muestra los primeros 10. Manipulando :limit y :offset, se pude obtener un paginado de los recursos.

2.2) Obtener registros en particular (x ID)

u = User.first
u = User.last
u = User.find 7
u = User.find [7, 9 , 10] # Entrega 3 elementos con ID: 7, 9 y 10

2.2.1) Tipos de respustas
Ante cada consulta AR nos puede devolver 2 tipos de objetos: un objeto AR (el que buscamos o solicitamos). O un arreglo de objetos AR:

u = User.first
u.class.to_s # => "User"
 
u = User.find [5,6,7]
u.class # => Array

Esto es muy importante a la hora de armar las vistas. Si nosotros solicitamos un objeto y AR no lo encuentra, nos devuelve “nil“, por lo que tendremos que contemplar esta posibilidad en la vista. En cambio cuando hacemos una solicitud de un arreglo, AR nos puede devolver: un arreglo de objetos (array), un arreglo con un único elemento o un arreglo vacío. Aquí no suelen aparecer problemas ya que en genera en la vista usamos: objeto.each do … y en caso de que el arreglo este vacío, no se da ninguna iteración, pero tampoco salta ninguna exeption.

2.3) Usando dynamic finders
En pos de la legibilidad rails genera “buscadores dinámicos” asociados a los atributos de la tabla:

# Devuelven un objeto AR
u = User.find_by_email "marcos@correo.com"
u = User.find_by_last_name "Vanetta"
u = User.find_by_first_name "Marcos"
 
# Devuelven un arreglo de objetos AR
p = Post.find_all_by_title "Et"

2.4) Búsquedas con condiciones

u = User.find :first_name => "Marcos"
u = User.find :all, :conditions => ["first_name = ?", "Natalie"]
u = User.all :conditions => ["first_name = ?", "Natalie"]
u = User.all :conditions => ["first_name = ? AND last_name = ?", "Natalie", "Erdman"]
u = Post.all :limit => 10, :offset => 0, :conditions => ["state <> ?", "unsearchable"]

2.5) Más condiciones

p = Post.all :limit => 10, :offset => 0, :conditions => ["state <> ? AND body LIKE ?", "unsearchable", "%Texto%"]
p = Post.all :conditions => ["user_id = ? AND state = ?", "2", "draft"]

2.6) Condiciones con un Array
p = Post.all :limit => 10, :conditions => ["state IN (?)", ["published", "draft"]]
Podemos notar tuvimos que agregar el IN(?) para que la consulta se haga de manera correcta.

2.7) Conditions’ hash

>> p = Post.all :conditions => {:state => ["published", "draft"]}
  Post Load (57.6ms)   SELECT * FROM `posts` WHERE (`posts`.`state` IN ('published','draft'))

Y, esta es la posta! Por que no necesitamos aclarar en la consulta si es un = on un IN.
Otro ejemplo:

>> u = User.all :conditions => {:last_name => nil}
  User Load (2.1ms)   SELECT * FROM `users` WHERE (`users`.`last_name` IS NULL)

2.8) Range conditions

>> p = Post.all :conditions => {:created_at => (Time.now.midnight - 1.day)..Time.now.midnight}
    Post Load (25.8ms)   SELECT * FROM `posts` WHERE (`posts`.`created_at` BETWEEN '2010-08-28 00:00:00' AND '2010-08-29 00:00:00') 
>> p = Post.all :conditions => {:user_id => (3..4)}
  Post Load (27.5ms)   SELECT * FROM `posts` WHERE (`posts`.`user_id` BETWEEN 3 AND 4)

Esta es la primer entrega de este mini tutorial. La idea es hacer un repaso de AR desde cosas super básicas como estas, hasta algunas un poco más avanzadas.

[1] http://es.wikipedia.org/wiki/Patr%C3%B3n_ActiveRecord
[2] http://api.rubyonrails.org/classes/ActiveRecord/Base.html
[3] http://blog.malev.com.ar/2010/08/04/bang-methods-in-activerecord/
[4] http://railscasts.com/episodes/15-fun-with-find-conditions

Post to Twitter Tweet This Post

, ,

Ubuntu trae instalado python por defecto:

malev@dell:~$ python -V
Python 2.6.5

Primero instalamos pip, pero para esto necesitamos python-setuptools:

sudo apt-get install python-setuptools

Bajamos pip de aquí [1], descomprimimos y hacemos:

sudo python setup.py
sudo ln -s /usr/local/bin/pip-2.6 /usr/bin/pip

Algunos intérpretes “bonitos”:

sudo apt-get install ipython bpython

Bazaar
Ya he hablado de este fantástico CVS [2] y hoy en día se ha convertido en una herramienta fundamental en mi trabajo con python, por lo que obligadamente tengo que hacer:

malev@dell:~/code$ sudo apt-get install bzr

Me le animo a virtualenv:

sudo pip install virtualenv
sudo pip install virtualenvwrapper

Creo un directorio para guardar mis proyectos:

mkdir /home/malev/dev

Agrego lo siguiente a ~/.bashrc:

export WORKON_HOME=~/dev
source /usr/local/bin/virtualenvwrapper.sh

Cierro y abro otra terminal.
Virtualenv ya está listo y a la espera :)

Usando virtualenv Basado en [3]

malev@dell:~/code$mkvirtualenv –distribute –no-site-packages stipple
(stipple)malev@dell:~/code$ cdvirtualenv
(stipple)malev@dell:~/dev/stipple$

Compruebo que no tengo ninguna librería de python instalada, salvo por distribute y wsgiref:

(stipple)malev@dell:~/dev/stipple$ pip freeze

Vuelvo a la normalidad:

(stipple)malev@dell:~/code$ deactivate

Vuelvo a trabajar con stipple:

malev@dell:~/code$ workon stipple

¿Cómo compartir mi entorno?
Cuando trabajamos en un proyecto con varias personas es necesario que todxs tengamos instaladas las mismas librerías. Virtualenv y pip nos ayudan a compartir nuestro entorno con nuestros amigxs:

malev@dell:~/dev/stipple$ workon stipple
(stipple)malev@dell:~/dev/stipple$ pip freeze > ~/stipple_env.txt

Enviamos este archivo a nuestrxs amigos y ellxs tendrán que hacer desde sus computadoras:

mkvirtualenv –distribute –no-site-packages stipple_en_otro_lugar
pip install -r ~/stipple_env.txt

Y así tendrán las mismas librerías que nosotros :)

Haciendo andar pygtk en nuestro entorno, ¿Cómo?
Este punto es bastante raro, por que pip install pygtk no funciona, para solucionarlo, yo instale pygtk2 usando apt-get y luego seguí las instrucciones de esta pregunta de stackoverflow:
http://stackoverflow.com/questions/249283/virtualenv-on-ubuntu-with-no-site-packages

Links:
[1] http://pypi.python.org/pypi/pip#downloads
[2] http://blog.malev.com.ar/2009/12/16/probando-bazaar
[3] http://www.youtube.com/watch?v=jI8VBP1wEZU&feature=related

Post to Twitter Tweet This Post

, ,

Este por no es para nada original, pero como tuve que reinstalar todo mi sistema, se me ocurrió aprovechar y sacar un post :) Mañana o cuando pueda voy a hacer uno de mi entorno python.

Instalar Ruby 1.8.7
Como Ubuntu te recomienda la versión 1.9.1 y esta todavía no es compatible con muchas gemas, prefiero dejarla de lado hasta más adelante.
Baje el .deb de ruby 1.8.7 de aquí [1].
No se por que el binario luego de la instalación se llama ruby1.8 y está ubicado aquí:

malev@dell:~$ which ruby1.8
/usr/bin/ruby1.8

Para evitar escribir ruby1.8 cada vez que lo necesito, voy a crear un link simbólico:

malev@dell:~$ sudo ln -s /usr/bin/ruby1.8 /usr/bin/ruby
malev@dell:~$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]

También instalo irb y rdoc:

sudo apt-get install irb
sudo apt-get install rdoc1.8
sudo apt-get install ruby1.8-dev
apt-get install libopenssl-ruby

Ahora a instalar rubygems
Bajo el .tgz de [2] lo descomprimimos y corremos:

malev@dell:~/Descargas/rubygems-1.3.7$ sudo ruby setup.rb install
RubyGems 1.3.7 installed

=== 1.3.7 / 2010-05-13

——————————————————————————

RubyGems installed the following executables:
/usr/bin/gem1.8

Otra vez, el binario se guarda con el 1.8 al final. Muy molesto, por lo que también le voy a crear un link simbólico para simplificarme la vida:

malev@dell:~/Descargas/rubygems-1.3.7$ sudo ln -s /usr/bin/gem1.8 /usr/bin/gem

Una vez que tenemos gem instalado, podemos instalar todas nuestras gemas favoritas, para ser un poco original, aquí voy a instalar Sinatra y wirble.

sudo gem install sinatra wirble hirb

Ya que estoy voy a probar algunas sugerencias de [3] para mejorar un poco la consola IRB. Por lo que todo esto va directo al ~/.irbrc:

require 'rubygems'
require 'wirble'
require 'hirb'
Wirble.init
Wirble.colorize
# hirb (active record output format in table)
Hirb::View.enable
 
# IRB Options
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:EVAL_HISTORY] = 200
 
# Log to STDOUT if in Rails
if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER')
  require 'logger'
  RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
  #IRB.conf[:USE_READLINE] = true
 
  # Display the RAILS ENV in the prompt
  # ie : [Development]>>
  IRB.conf[:PROMPT][:CUSTOM] = {
   :PROMPT_N => "[#{ENV["RAILS_ENV"].capitalize}]>> ",
   :PROMPT_I => "[#{ENV["RAILS_ENV"].capitalize}]>> ",
   :PROMPT_S => nil,
   :PROMPT_C => "?> ",
   :RETURN => "=> %s\n"
   }
  # Set default prompt
  IRB.conf[:PROMPT_MODE] = :CUSTOM
end
 
# We can also define convenient methods (credits go to thoughtbot)
# def me
#  User.find_by_email("me@gmail.com")
# end

MySQL y SQLite:

sudo apt-get install mysql-server sqlite3 libmysql-ruby
sudo apt-get install build-essential libmysqlclient-dev libmysql-ruby libsqlite3-ruby libsqlite3-dev
apt-get install ruby-dev libmysql-ruby libmysqlclient-dev
sudo gem install rails mysql sqlite3-ruby mongrel

RVM: Ruby Version Manager [5]
Estoy leyendo un libro sobre ruby 1.9 y quiero ir probando algunos ejemplos. RVM es la mejor ( y creo que única ) alternativa para poder instalar varias versiones de Ruby en un solo entorno. Aquí solo sigo las instrucciones de la página. Y una vez terminado, pues:

rvm install 1.9.2

Links:
[1] http://ns2.canonical.com/es/lucid/i386/ruby1.8/download
[2] http://rubygems.org/pages/download
[3] http://www.tech-angels.fr/post/963080350/improve-irb-and-fix-it-on-mac-os-x
[4] http://tagaholic.me/2009/03/13/hirb-irb-on-the-good-stuff.html
[5] http://rvm.beginrescueend.com/

Post to Twitter Tweet This Post

, , ,

Para ver todas las tareas rake disponibles en un proyecto rails solo es necesario:

rake -T

Para ver todas las rutas disponibles: (además de revisar routes.rb)

rake routes

Ya se que es un post muy pobre, pero busque mucho esta info :)
Cómo mostrar las queries que genera ActiveRecord en la consola:

ActiveRecord::Base.logger = Logger.new(STDOUT)

Otra opción: en otra terminal escribir:

tail -f log/development.log

Cuando cambiamos un modelo, para no tener que reiniciar la consola, escribimos en la misma: reload!

Post to Twitter Tweet This Post

, ,

Acire[1][2] es una pequeña y simple herramienta para administrar spippets o recortes de código. Principalmente / exclusivamente contiene código python, pero para muchos usos. Los snippets se encuentran ordenados en categorías y están convirtiendo acire en una herramienta muy útil a la hora de desarrollar en python. Hay ejemplos para trabajar con couchDB, PyGTK, Zeitgeist, dbus, etc. Así que si planeas empezar algún proyectito nuevo, antes revisa a ver si ya hay algún código que te pueda ayudar.

Acire es un proyecto de Jono Bacon[3], actual community manager de Ubuntu, es libre y cualquiera puede enviar sus propios snippets, solo tiene que seguir estos pasos[4] y aquí hay una lista con los principales contribuyentes[5].
Cómo instalar Acire:

sudo add-apt-repository ppa:acire-team/acire-releases
sudo apt-get update
sudo apt-get install acire
# Instalar snippets
sudo add-apt-repository ppa:python-snippets-drivers/python-snippets-daily
sudo apt-get update
sudo apt-get install python-snippets

Sitios de interes:
[1] Sitio oficial de Acire
http://aciresnippets.wordpress.com
[2] Branch en launchpad
https://launchpad.net/acire

[3] http://www.jonobacon.org
[4] http://aciresnippets.wordpress.com/contribute/
[5] http://www.jonobacon.org/2010/03/30/acire-and-python-snippets-rockstars/

Post to Twitter Tweet This Post

, ,

Leyendo [1] descubrí la diferencia entre save y save! en ActiveRecord:

@user #=> ActiveRecord Instance
@user.save  # También podría ser: @user.update_atributes(params)
@user.save! # =>  @user.update_atributes!(params)

La 2da opción (línea 3) llama al método save bang (!) [2] a diferencia de la línea 2 que llama al save común. ¿Cuál es la diferencia? La respuesta viene de la mano de las validaciones (validations). Si @user no cumple con las validations, el save común devolverá false, mientras que save! levantará una excepción (ActiveRecord::RecordInvalid) [3].
Por otro lado, los métodos: create y update devuelven el mismo objeto si se actualizó o no la base de datos. Entonces cómo vamos a saber si un registro es válido para ser guardado, pues con el método: valid? O su gemelo malvado: invalid?

¿Cómo saltearnos las validaciones?

@objeto.save(false)

[1] http://guides.rubyonrails.org/activerecord_validations_callbacks.html
[2] https://wincent.com/wiki/Ruby_%22bang%22_methods
[3] http://apidock.com/rails/ActiveRecord/Base/save!

Post to Twitter Tweet This Post

, , ,

Hasta el 25 de Setiembre, día en que en las charlas abiertas de Python Argentina se tocará el tema de Interfaces gráficas de escritorio, falta un poquito.
Si no estas en Buenos Aires o quieres ir aprendiendo algo antes, te recomiendo este screencast de parte de Paul, editor de tuxradar. Allí podremos ver una rápida introducción al mundo de PyGTK a través de una consola, lo cual es muy bueno, por que podremos ir probando todo lo que el hace, nosotros mismos :)
Lamentablemente no se zambulle en Glade, pero como para empezar esta buenísimo!

Link al post de tuxradar: http://www.tuxradar.com/content/python-pygtk-webkit-20-minutes
Link al video en OGG theora: 44mb
Link al video en H.264: 56mb

Post to Twitter Tweet This Post

, ,

Hace unos días encontre este post de envylabs [1] en que muestran un video con una charla de Joe Damato [2] sobre el Garbage colector [3] y el heap[4] de Ruby. La conclusión y el pensamiento de muchos desarrolladores de Ruby no es muy alentador y titula este post. Pero en la charla nos dan algunos consejos de como optimizar el manejo de memoria.

Presentación:
Garbage Collection and the Ruby Heap

Si les gusto (como a mi) y quieren seguir leyendo al respecto (cosa que pienso hacer pronto), pueden pasear por aquí [5] y aquí [6].

Links:
[1] http://blog.envylabs.com
[2] http://timetobleed.com
[3] http://es.wikipedia.org/wiki/Recolector_de_basura
[4] http://es.wikipedia.org/wiki/Mont%C3%ADculo_%28inform%C3%A1tica%29
[5] http://blog.pluron.com/2008/01/ruby-on-rails-i.html
[6] http://www.coffeepowered.net/2009/06/13/fine-tuning-your-garbage-collector/

Post to Twitter Tweet This Post

, , ,

Continuando con el post anterior. Cuando RESTful parece no alcanzar y cuando nuestros recursos empiezan a tener hijos necesitamos de los recursos anidados (nested resources). Aquí usaremos los mismos ejemplos de [1].
Suponemos que tenemos una tabla revistas (magazines) y cada revista a su vez tiene publicidades (ads). Tendríamos los modelos:

class Magazine < ActiveRecord::Base
has_many :ads
end
 
class Ad < ActiveRecord::Base    
  belongs_to :magazine
end

En routes.rb configuramos:

map.resources :magazines do |magazine|
  magazine.resources :ads  
end  
# o la versión corta: 
# map.resources :magazines, :has_many => :ads.

Tendremos como resultado, las siguientes rutas:

Verb URL controller action used for
GET /magazines/1/ads Ads index display a list of all ads for a specific magazine
GET /magazines/1/ads/new Ads new return an HTML form for creating a new ad belonging to a specific magazine
POST /magazines/1/ads Ads create create a new ad belonging to a specific magazine
GET /magazines/1/ads/1 Ads show display a specific ad belonging to a specific magazine
GET /magazines/1/ads/1/edit Ads edit return an HTML form for editing an ad belonging to a specific magazine
PUT /magazines/1/ads/1 Ads update update a specific ad belonging to a specific magazine
DELETE /magazines/1/ads/1 Ads destroy delete a specific ad belonging to a specific magazine

Que en hacen uso de las acciones: index, new, create, show, edit, update y destroy. Pero todas haciendo referencia a una magazine que la contiene. También nos genera los helpers: magazine_ads_url, edit_magazine_ad_path, etc.
¿Cómo viajan los parámetros? Si ingresamos una URL: magazines/1/ads2 tendríamos un:

params = {"magazine_id"=>"1", "action"=>"show", "id"=>"2", "controller"=>"ads"}

Otra forma de generar los links (en un link_to) es con arreglos:

<%= link_to "Ad details", magazine_ad_path(@magazine, @ad) %># un link a show

También podemos usar :name_prefix para configurar un poco más nuestras rutas anidadas:
1) Cambiarle el nombre

map.resources :magazines do |magazine| 
  magazine.resources :ads, :name_prefix => 'periodical' 
end

2) Ocultar el prefijo:

map.resources :magazines do |magazine| 
  magazine.resources :ads, :name_prefix => nil 
end

nota: en este último caso necesitaremos pasar por parámetros el id del magazine en los helpers: ads_url(@magazine) y edit_ad_path(@magazine, @ad).

Resources únicos:

map.resources :photos do |photo|
  photo.resource :photographer
end
# o la forma corta:
# map.resources :photos, :has_one => :photographer

Por último, cuando queremos crear un nuevo elemento, ¿Cómo armamos el formulario? pues con:

<% form_for([ @magazine, @ad ]) do |f| %>

[1] http://guides.rubyonrails.org/routing.html

Post to Twitter Tweet This Post

, , ,