Aquí en Venezuela, muchas cosas son modismos. La gente compra lo que los demás compran. La mayoría no se pregunta si es lo mejor (para el dinero que puede gastar), o si al menos es lo que en realidad necesita.

Aquí, la moda es cualquier cosa menos el iPhone, el otro día la hija de una amiga me preguntó si mi teléfono era un iPod (touch) y sin muchos detalles yo le respondí:

No, es un iPhone. Es como un iPod Touch pero con teléfono, GPS y cámara.

A lo que ella respondió:

Ahh, ese es chimbo, mejor es un BlackBerry.

De necio, le pregunté

¿Por qué?

y me respondió:

El BlackBerry tiene Live Messenger.

Por razones obvias la conversación llegó hasta ahí. No uso Windows Live Messenger ni en mi computadora, y si existiera para Linux tampoco lo usaría, prefiero una sola aplicación que me mantenga conectado a todos los sistemas de mensajerías y redes sociales (cuando me conecto).

El punto es que muchos Venezolanos (jóvenes y adultos) son así. ¿El iPhone es chimbo porque no es el que está de moda aqui o porque no tiene Windows Live Messenger?. El problema es que no están acostumbrados a evaluar un producto por su usabilidad, sino por la cantidad de "features" que tiene, cuando es bien sabido que muchas veces menos es mas, sobre todo en software (que es lo que tienen "adentro" los teléfonos estos).

Algunas de mis razones para tener un iPhone en vez de un BlackBerry

  1. Usabilidad: Después de varios días de uso, leí el manual en línea para ver si había cosas que aún no sabía como hacer en el iPhone. El manual impreso que trae no dice casi nada, porque el iPhone está diseñado "for dummies", se siente como si el teléfono se anticipa a lo que quieres hacer. Cada aplicación está cuidadosamente pensada en el usuario final, además, la pantalla táctil, con multitouch funciona a las mil maravillas.

  2. Menos es mas: Si bien existen cosas que el iPhone no posee, es debido a que en realidad no son de uso tan común, o no dan un valor agregado real a la experiancia de uso. Además, la rápida evolución de su sistema operativo incorpora lo necesario en sus actualizaciones. bold_iphone.jpg

  3. Diseño: "Designed in California. Assembled in China"... el BlackBerry Bold, por ejemplo, es horroroso, el teclado es mas de la mitad del teléfono!!!. El acabado del iPhone es impecable.

  4. Precio: Yo compré mi iPhone 3G de 8GB por algo menos de 2000 BsF. Si se compara por ejemplo con el BlackBerry Storm... vale como 3.700 BsF.

  5. Aplicaciones: En la Apple Store hay de todo y para todos.

  6. Desarrollo: Espero en un futuro cercano comenzar a probar el desarrollo de aplicaciones para el iPhone, es una oportunidad de negocio y creo que puede ser bastante fructífera. logo-apple.jpg

  7. El fabricante: No necesito decir mas... cada producto de Apple está cuidadosamente diseñado, tienen algo que lo identifica como de Apple.

Existen muchas cosas más que no voy a detallar en este artículo, hay muchos reviews en internet. Tampoco quiero decir que nadie deba usar un BlackBerry u otro teléfono, simplemente creo que todos debemos sentarnos y pensar que es lo que nos sirve, lo que se ajusta a nosotros y lo que podemos gastar, pero no comprar por modismos. Por ejemplo, muchas personas se la pasan intercambiando sus pin del BlackBerry. En mi caso, no tengo casi conocidos con BlackBerry (o conocidos que me interese estar en constante contacto) y no me gusta estar pegado en el teléfono escribiendo mensajitos, simplemente prefiero llamar o enviar un SMS.

Saludos!

passionate_programmer_cover.jpg Actualmente estoy leyendo el nuevo libro de Chad Fowler, The Passionate Programmer, me llegó hace poco desde Amazon.

¿Cómo dí con este libro? Bueno, en realidad soy un lector frecuente de las publicaciones de The Pragmatic Bookshelf y siempre estoy pendiente de sus libros nuevos. Decidí comprarlo cuando leí los extractos que ellos publican (para enamorar a uno... :p), en especial el del capítulo Be the Worst. El asunto es que Chad Fowler además de programador es músico (de hecho era saxofonista profesional antes de ser un programador), de ahí la portada del libro.

Mis amigos saben que he sido violinista casi toda mi vida (ahorita es que lo tengo medio abandonado... pero no por mucho, me pican las manos para finalizar el Sibelius y la Sonata 3 -Ballade- de Ysaÿe). También saben que estuve trabajando para una contratista en PDVSA por mas de 3 años. Lo que no deben saber muchos es que, me fuí (o me botaron, como lo prefieran), al igual que varios compañeros, que actualmente estamos juntos aquí en COTECSO, iniciando una Cooperativa de desarrollo de software, adiestramiento, etc.

The Passionate Programmer trata de Cómo crear o tener una carrera "remarcable" en el mundo del desarrollo de software, y no es que antes yo o alguno de nosotros en COTECSO fuera malo, pero como asalariado todo es mas fácil (al principio) y hay cierta sensación de seguridad, se está en el anonimato, tras las paredes de una gran compañía, nadie sabes que existes. Yo diría que es seguro mas no gratificante. Pero, como emprendedores, necesitamos dar a conocer nuestras habilidades, necesitamos proyectarnos en la comunidad de desarrollo de software, crear productos, invertir en conociemiento, ser mejores... ser exitosos.

Compré The Passionate Programmer porque trata estos temas, con consejos para crear esa carrera "remarcable" como desarrollador de software y porque lo escribió un músico con una pasión sobre las computadoras. De hecho, a medida que voy avanzando en el libro, me he visto retratado en muchas de las anécdotas y experiencias que allí se relatan. Además, está lleno de ejemplos e historias motivadoras de gente exitosa en el mundo del software. Es obvio que está escrito por alguien a quién le apasiona lo que hace.

Al final, los músicos siempre quieren ser mejores, quieren ser "geniales" (para no decir vergatarios!) y eso requiere trabajo, dedicación, constancia, paciencia e "invertir" en uno mismo. Parafraseando a Chad Fowler: hay muchos buenos músicos que son también muy buenos desarrolladores de software, y no es porque piensen igual, o que ambos sean paranóicos con el detalle (pregúntenle a un violinista) o sean creativos. La razón es que una persona que en realidad quiere ser genial y exitosa (como un músico) tiene mas probabilidad de serlo que alguien que sólo quiere hacer su trabajo.

Saludos!

Actualmente estamos comenzando un proyecto que consta de unos ajustes a una aplicación en Rails que utiliza una versión vieja de este framework (1.2.3) y por razones de tiempo y costo, no es posible realizar una actualización a una versión mas nueva (2.x).

En mi caso, por ser un desarrollador con Ruby y con Rails, no puedo darme el lujo de hacer un downgrade total a versiones viejas, incluso, Rails 1.2.3 no es compatible con los últimos patchlevel (actualizaciones varias y de seguridad) de Ruby 1.8.6 ni con Ruby 1.8.7 (ni pensar Ruby 1.9). Mi laptop actualmente tiene Ubuntu Jaunty (9.04), por lo que Ruby es de la serie 1.8.7.

Mi solución fue instalar Ruby Enterprise de Phusion, y mantener una instalación paralela en /opt. Pero una de las extensiones que necesitaba instalar era ruby-ldap, que para hacer las cosas más interesantes, la compilación fallaba, las razones se explican aquí.

Para resumir, la versión de libldap2 incluida en Ubuntu Jaunty no es compatible con ruby-ldap 0.9.7 ni con el último ruby-ldap 0.9.8, por lo que la solución era descargar una versión anterior de las librerías de OpenLDAP (la estable del 2008) y compilar ruby-ldap contra estas librerías.

Para agregarle mas interés a todo el embrollo, resulta que la compilación de openldap-2.4.11 (la estable del 2008), también generaba error, ¿la razón?, básicamente, esa versión de OpenLDAP no compila con GCC 4.3. Gracias a la gente de mi antigua y aún muy querida favorita distribución Gentoo, pude compilar las librerías de OpenLDAP gracias a un patch suministrado por ellos, descargable aquí.

Instalación

A continuación los pasos de esta mini-odisea para dejar documentada la solución, tanto para mí como para la comunidad.

El primer paso es instalar Ruby Enterprise (pero primero unas dependencias, que el mismo instalador de Ruby Enterprise solicitará si no se encuentran instaladas)

sudo aptitude install libssl-dev libreadline5-dev

Luego, descomprimir el tarball de Ruby Enterprise e instalar (seguir instrucciones del instalador de línea de comando):

tar xzvf ruby-enterprise-1.8.6-20090520.tar.gz
cd ruby-enterprise-1.8.6-20090520/
sudo ./installer

Ruby Enterprise es instalado por defecto en /opt, para facilitar el acceso a los ejecutables, realizaremos enlaces simbólicos a /usr/bin:

sudo ln -s /opt/ruby-enterprise-1.8.6-20090520/bin/ruby  /usr/bin/rubye
sudo ln -s /opt/ruby-enterprise-1.8.6-20090520/bin/gem  /usr/bin/geme
sudo ln -s /opt/ruby-enterprise-1.8.6-20090520/bin/irb  /usr/bin/irbe

Nótese que los symlinks se llaman igual, pero finalizan con "e" de Enterprise. Por lo tanto para utilizar Ruby Enterprise, desde la línea de comando sólo debemos utilizar rubye, y para instalar gemas utilizamos geme.

Antes de compilar la extensión ruby-ldap, instalar las librerías de OpenLDAP, en este caso utilizaremos como destino /opt/openldap, para evitar conflictos con las librerías existentes en el sistema (Nota: reemplazar openldap_patch.diff por el nombre asignado al momento de descargar el Patch OpenLDAP para GCC 4.3 o superior):

tar xzvf openldap-stable-20080813.tgz 
cp openldap_patch.diff openldap-2.4.11/
cd openldap-2.4.11/
patch -p1 < openldap_patch.diff 
./configure --prefix=/opt/openldap --enable-slapd=no
make depend
make 
sudo make install

Ahora se procede a instalar ruby-ldap 0.9.7, descomprimir el tarball e instalar, indicando las librerías de ldap en /opt/openldap:

tar xzvf libldap-ruby_0.9.7.orig.tar.gz
cd ruby-ldap-0.9.7/
rubye extconf.rb --with-ldap-dir=/opt/openldap
make
sudo make install

Nótese el uso de rubye para la configuración de la extensión.

Instalar las gemas necesarias (nótese el uso de geme y no gem):

sudo geme install rails -v x.x.x
# ...

Adicionalmente, para facilitar el acceso al rake de la instalación de Ruby Enterprise, creé un enlace simbólico a /usr/bin (igual que con rubye, irbe y geme):

sudo ln -s /opt/ruby-enterprise-1.8.6-20090520/bin/rake  /usr/bin/rakee

Como observación, los scripts de línea de comando de Rails (por ejemplo, script/server), deben invocarse con rubye -S. Ejemplo:

## Iniciar el servidor local de desarrollo
rubye -S script/server

## Iniciar la cónsola de la aplicación
rubye -S script/console --irb=irbe

## Las Tareas rake debe utilizar rakee
rakee db:migrate 

Saludos!

Esta es la segunda parte de una serie de 3 artículos sobre la presentación que realicé en el FLISOL Paraguaná 2009.

Imagen Thumbnail para flisol_todo_borrador_interfaz.png

En la primera parte, explicamos brevemente en qué consistiría la aplicación, generamos el proyecto con Rails, generamos el scaffold para el modelo Tarea y agregamos una que otra validación en el modelo. En esta segunda parte, lo que haremos es darle un poquito de forma, para que parezca al borrador que dibujamos durante la primera parte.

Vemos en el borrador que tenemos claramente separadas las tareas finalizadas de las pendientes, por tanto debemos definir una manera de buscar dichas tareas. ActiveRecord nos brinda muchas opciones para realizar esta labor, en este caso usaremos los named_scopes, aunque esto podría considerarse un overkill es un buen ejemplo de la fantástica semántica que Rails pone a nuestra dispocición. Editamos el modelo Tarea (app/models/tarea.rb), y agregamos al final lo siguiente:

  named_scope :pendientes, :conditions => {:finalizada => false}
  named_scope :finalizadas, :conditions => {:finalizada => true}

Esto nos va a permitir buscar las tareas pendientes y finalizadas de la siguiente manera:

Tarea.pendientes    # => devuelve las tareas pendientes
Tarea.finalizadas   # => devuelve las tareas finalizadas

Sabiendo como buscar las tareas finalizadas y las pendientes, ahora podemos asignarlas tranquilamente a variables de instancia en TareasController#index. Editamos la acción index del controlador TareasController (app/controllers/tareas_controller.rb) para que quede de la siguiente manera:

# GET /tareas
  # GET /tareas.xml
  def index
    @pendientes = Tarea.pendientes
    @finalizadas = Tarea.finalizadas
    @tarea = Tarea.new

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @tareas }
    end
  end

Lo que hicimos fue eliminar la búsqueda original que retornaba todas las tareas, pendientes y finalizadas, y agregamos 2 búsquedas nuevas: Tarea.pendientes y Tarea.finalizadas. Adicionalmente agregamos la variable de instancia @tarea, que contiene una Tarea nueva (vacía), esto se debe a que en nuestra página index (según el borrador), vamos a incluir un formulario en la parte inferior para agregar nuevas tareas.

El siguiente paso es hacerle algunos ajustes a nuestra interfaz para que se parezca mas a nuestro diseño de lápiz y papel. Lo primero, cambiar el markup de la vista, editamos app/views/index.html.erb para que se vea así:

<h1>Mis tareas</h1>

<h2>Pendientes</h2>

<% if @pendientes.any? %>
  <ul class="tareas pendientes">
    <%= render :partial => @pendientes %>
  </ul>
<% else %>
  <p class='sin-tareas'>No hay tareas pendientes</p>
<% end %> 

<% if @finalizadas.any? %>
  <h2>Finalizadas</h2>

  <ul class="tareas finalizadas">
    <%= render :partial => @finalizadas %>
  </ul>
<% end %> 

<hr />

<%= render :partial => "form" %>

¿Qué hicimos? Ya deben haberse dado cuenta que eliminamos la tabla (tag table) para mostrar el listado de tareas, ahora, cada conjunto de tareas se muestran con una "unordered list" (ul). Se agregaron 2 títulos de segundo nivel (h2) para dividir las tareas finalizadas de las pendientes. Adicionalmente, las pendientes y las finalizadas se muestran siempre y cuando existan registros asociados a la misma (if @pendientes.any?, if @finalizadas.any?). Como podrán haberse dado cuenta, en el template aparencen unos fulanos render :partial => algo. El método render, para resumirlo, es uno de los mecanismos con los cuales se envía contenido al usuario (detalles en la api de Rails - Partials).

Rails es lo suficientemente inteligente para determinar que @pendientes y @finalizadas contienen un conjunto de objetos Tarea (ver RecordIdentifier, por tal razón, tanto render :partial => @pendientes como render :partial => @finalizadas lo que hacen es mostar el partial (fragmento de vista) tarea/_tarea.html.erb para cada uno de los elementos dentro de las variables @pendientes y @finalizadas. Nota: los parials en Rails siempre comienzan con "_". Ej: _tarea.html.erb. Rails determina este nombre gracias a RecordIdentifier#partial_path.

render :partial => "form" lo que hace es mostrar el partial _form.html.erb (Nótese que no es necesario especificar el "_").

Hablamos de varios partials (_tarea.html.erb y _form.html.erb), pero no los hemos creado. Eso es lo que vamos hacer ahora mismo. Primero, creamos el archivo _tarea.html.erb en app/views/tareas y agregamos el siguiente contenido:

<li>
  <% form_for(tarea) do |f| %>
    <%= f.check_box :finalizada, :onchange => 'form.submit();' %>
    <%= h tarea.titulo %>
    <span><%= tarea.notas %></span>
    <%= link_to 'Editar', edit_tarea_path(tarea) %>
    <%= link_to 'Eliminar', tarea, :confirm => 'Seguro que desea eliminar la tarea?', :method => :delete %>
  <% end %>
</li>

Este partial se encargará de mostrar cada elemento (o list item li) de la lista ul. La representación de cada tarea en el navegador es un formulario, que incluye un check_box, el cual al hacerle clic realiza el submit de dicho formulario. El resto es el título y las notas de la tarea, con los links de edición y eliminación.

Ahora, creamos el partial del formulario para agregar nuevas tareas (app/views/tareas/_form.html.erb):

<h2>Agregar nueva tarea</h2>

<% form_for(@tarea) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :titulo %><br />
    <%= f.text_field :titulo %>
  </p>
  <p>
    <%= f.label :notas %><br />
    <%= f.text_area :notas %>
  </p>
  <p>
    <%= f.submit 'Agregar' %>
  </p>
<% end %>

Este partial es una versión simplificada del template new.html.erb generado por el scaffold en la parte 1. De hecho, ese template original no va a ser utilizado, así que lo podemos eliminar.

Podríamos probar la aplicación en este momento, pero nos daríamos cuenta de que no se parece a nuestro borrador de lapiz y papel. ¿La razón?, debemos agregar una hoja de estilo simple para darle el "look" que deseamos. Creamos el archivo public/stylesheets/todo.css con el siguiente contenido:

/*Hoja de estilos principal de FLISOL todo*/

h1 {
  background-color: #333;
  padding: 10px;
  color: #FFF;
}

h2 {
  padding-top: 20px;
}

hr { margin-top: 20px; margin-bottom: 20px;}

ul.tareas li {
  padding-left: 0;
  padding-top: 15px;
  list-style: none;
  font-weight: bold;
}

ul.tareas li span {
  display: block;
  font-style: italic;
  font-weight: normal;
  padding-bottom: 5px;
}

ul.tareas li a {
  font-size: 10px;
}

ul.pendientes li {
  font-size: 16px;
  margin-top: 8px;
}

ul.pendientes li span {
  color: #333;
  font-size: 14px;
}

ul.finalizadas li {
  color: #999;
  font-size: 12px;
}

ul.finalizadas li span {
  color: #666;
  font-size: 11px;
}

p.sin-tareas {
  color: #338;
  font-style: italic;
  margin-left: 45px;
}

textarea { height: 50px; }

Sólo nos falta hacer referencia a esta hoja de estilo en nuestro layout. Buscamos la línea:

<%= stylesheet_link_tag 'scaffold' %>

y la reempalzamos por:

<%= stylesheet_link_tag 'scaffold', 'todo' %>

Ahora podemos probar la aplicación en http://localhost:3000/tareas.

Después de navegar, nos daremos cuenta de que hay un comportamiento extraño al momento de editar, eliminar o crear una tarea, esto se debe a que en TareasController, estas acciones deben redirigir a index luego de realizar su trabajo:

class TareasController < ApplicationController

  # GET /tareas
  # GET /tareas.xml
  def index
    @pendientes = Tarea.pendientes
    @finalizadas = Tarea.finalizadas
    @tarea = Tarea.new

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => (@pendientes + @finalizadas) }
    end
  end

  # GET /tareas/1
  # GET /tareas/1.xml
  def show
    @tarea = Tarea.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @tarea }
    end
  end

  # GET /tareas/new
  # GET /tareas/new.xml
  def new
    @tarea = Tarea.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @tarea }
    end
  end

  # GET /tareas/1/edit
  def edit
    @tarea = Tarea.find(params[:id])
  end

  # POST /tareas
  # POST /tareas.xml
  def create
    @tarea = Tarea.new(params[:tarea])

    respond_to do |format|
      if @tarea.save
        flash[:notice] = 'La tarea se creó satisfactoriamente.'
        format.html { redirect_to tareas_path }
        format.xml  { render :xml => @tarea, :status => :created, :location => @tarea }
      else
        @pendientes = Tarea.pendientes
        @finalizadas = Tarea.finalizadas
        format.html { render :action => "index" }
        format.xml  { render :xml => @tarea.errors, :status => :unprocessable_entity }
      end
    end
  end

  # PUT /tareas/1
  # PUT /tareas/1.xml
  def update
    @tarea = Tarea.find(params[:id])

    respond_to do |format|
      if @tarea.update_attributes(params[:tarea])
        flash[:notice] = 'La tarea fue actualizada.'
        format.html { redirect_to tareas_path }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @tarea.errors, :status => :unprocessable_entity }
      end
    end
  end

  # DELETE /tareas/1
  # DELETE /tareas/1.xml
  def destroy
    @tarea = Tarea.find(params[:id])
    @tarea.destroy

    respond_to do |format|
      format.html { redirect_to(tareas_url) }
      format.xml  { head :ok }
    end
  end
end

flisol_todo_con_estilos_aplicados.png

Nótese que las acciones create y update redirigen a index si la operación fue satisfactoria, esto se logra mediante redirect_to tareas_path. Otro pequeño ajuste se realizó para el caso de que la operación de creación de una nueva tarea falla: se debe mostrar el template index.html.erb, pero para evitar un error de que no se encuentran definidas las variables @pendientes y @finalizadas, debemos asignarles los registros tal cual se realizó en la acción index.

Si todo salió bien, debemos ver algo parecido a lo que se muestra en la imagen.

Bueno, eso es todo en esta parte 2, en la siguiente entrega mostraremos las tareas pendientes y finalizadas en el iphone, utilizando mi plugin rails_jqtouch.

Saludos!

rails_jqtouch_screenshot.png Hace un par de semanas, publiqué en mi github, un plugin de Rails llamado rails_jqtouch para facilitar el uso de jQTouch con Rails. jQTouch es un plugin de jQuery que facilita el desarrollo de aplicaciones web para dispositivos móviles con navegador Mobile Webkit, como por ejemplo un iPhone de Apple, HTC G1 o Palm Pre.

Hace como un mes, estaba viendo que demostración hacía para el FLISOL Paraguaná 2009, obviamente, por ser desarrollador en Ruby, el tema era algo de Rails (además de poder hacer publicidad para los cursos de Rails!!), pero no es fácil mostrarle a jóvenes (no es que yo me sienta viejo!!, tengo 26 años!!) que están comenzando en este mundo de desarrollo de software las bondades de Rails, así que decidí colocarle un aderezo interesante a la demostración... incluir la participación de mi flamante iPhone 3G :p

El asunto era ¿cómo?, comencé a adentrarme en el desarrollo de aplicaciones web para estos dispositivos, probé varias alternativas que incluían: iUI, rails_iui y tank_engine (los dos últimos cortesía de Noel Rappin (Por cierto me acabo de enterar que ha escrito como 3 libros!!!). Para resumir, ninguno me complació del todo, de repente, me encontré con jQTouch en Ajaxian, el asunto era que no era fácil hacer la demostración de Rails y jQTouch sin un plugin, así que me animé a crearlo y tenerlo listo para el FLISOL. Además era algo importante para mí, ya que nunca había liberado un código fuente y era algo que simplemente debía hacer (antes tenía una camisa de fuerza cuando trabajaba en PDVSA).

Ok... basta de reseñas históricas, vamos a mostrar algunas funcionalidades de jQTouch.

Instalación

Para instalar rails_jqtouch, lo único que hay que hacer es descargarlo desde mi github, o más fácilmente, instalarlo directamente con script/plugin install desde un proyecto de Rails:

script/plugin install git://github.com/rrodrigu3z/rails_jqtouch.git

rails_jqtouch incluye varias tareas rake que facilitan, por ejemplo, la copia de los archivos de jQTouch (javascripts, imágenes, stylesheets, etc) dentro de los directorios correctos del proyecto. En este sentido, el siguiente paso es ejecutar:

rake rails_jqtouch:install

Algunas de las otras tareas disponibles son (ejecutar rake -T para ver todas):

rake rails_jqtouch:jqtouch_version  # Show jQTouch version included
rake rails_jqtouch:clean            # Delete all installed files

Uso: Controladores

Al igual que rails_iui, rails_jqtouch puede reconocer los requests provenientes de navegadores Mobile Safari, para ello se debe incluir en el controlador deseado o en el ApplicationController lo siguiente:

acts_as_iphone_controller

Con esto, habilitamos al controlador para que pueda incluirse la opción :iphone dentro de bloques respond_to, por lo que podemos crear templates con nombres tipo xxxx.iphone.erb.

Ejemplo:

class TareasController < ApplicationController
  acts_as_iphone_controller

  # GET /tareas
  # GET /tareas.iphone
  # GET /tareas.xml
  def index
    @tareas = Tarea.all

    respond_to do |format|
      format.html     # index.html.erb
      format.iphone   # index.iphone.erb
      format.xml  { render :xml => @tareas }
    end
  end

  # Otras acciones ...

end

Uso: Helpers y Vistas

rake rails_jqtouch:install también copia un layout de ejemplo en app/views/layouts/application.iphone.erb, el cual puede ser ser personalizado según las necesidades:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Rails JQTouch</title>

    <%= stylesheet_link_tag "jqt/jqtouch" %>
    <%= javascript_include_tag "jquery-1.3.2.min", "jqtouch.min" %> 
    <%= jqtouch_init :status_bar => "black-translucent" %>
</head>
<body>
  <%= yield %>
</body>
</html>

Con jqtouch_init se puede configurar el comportamiento de jQTouch, para detalles de las opciones soportadas, ver la documentación de jQTouch (aunque no hay mucha que se diga aún).

Jqtouch::MobileHelper define helpers que son incluidos de manera automática, y que facilitan la escritura de los templates, los detalles están en la documentación del código. Algunos ejemplos de uso también se pueden ver en los tests. De todas formas colocaré algunos ejemplos y formas de uso aquí en el blog.

<% mobile_page 'home', :selected => true do  %>
  <% mobile_toolbar 'jQTouch' do %>
    <%= mobile_button_to "About", '#about', :effect => 'slideup' %>
  <% end %>

  <%= mobile_list [
      {:name => "Features", :url => "#features"},
      {:name => "Demos", :url => "#demos"},
      {:name => "Docs", :url => "docs.html"},
      {:name => "License", :url => "#license"},
      {:name => "Download &raquo;", :url => "http://www.jqtouch.com/", :target => "_self"} ]  %>

<% end %>


<% mobile_panel 'about' do %>
  <% mobile_pad :style => 'padding-top: 80px' do %>
    <p>jQTouch was created by David Kaneda as a means of easily creating iPhone-styled websites. 
    It is released open source, under the MIT license. It is still in its early stages of development 
    and is currently lacking in documentation. 
    For more information about jQTouch, please contact 
    <a href="http://twitter.com/davidkaneda/">David on Twitter, @davidkaneda.</a></p>

    <%= mobile_back_button 'Close', :class => "grayButton"  %>
  <% end %> 
<% end %>

El listado anterior es un fragmento adaptado con rails_jqtouch del index.html incluido como ejemplo con jQTouch. Algunos de los helpers incluidos en rails_jqtouch son:

  • mobile_page: Genera el wrapper para una página, referenciada por un id.
  • mobile_pad: Genera un div con la clase pad, que sirve de contenedor de elementos de formulario, texto, entre otros.
  • mobile_panel: Es como mobile_page, pero le agrega al div resultante la clase panel.
  • mobile_fieldset: Genera un fieldset, que sirve de contenedor de mobile_rows.
  • mobile_row: Genera un div con la clase row que se utiliza como contenedor de elementos de formulario.
  • mobile_toolbar: Genera la barra de herramientas.
  • mobile_button_to: Genera un botón con los estilos deseados.
  • mobile_back_button_to: Genera un botón para devolverse, útil para ser usado en el toolbar.
  • mobile_list: Genera una lista, típica de aplicaciones para móviles, se puede especificar el nombre y url de cada item.

Como mencioné antes, la documentación está mucho mejor en el código, por lo que pueden generarla con rdoc. Si tengo tiempo, la subo en estos días a algún subdominio para que esté en línea.

Bueno, espero que este plugin sea de utilidad, no soy un experto en desarrollo para dispositivos móviles, pero espero sus comentarios, sugerencias, mejoras, etc. Además, es mi primer código que libero, así que sean gentiles!!! (por si ven algún mamarracho...).

Saludos! y estén pendientes para la siguiente parte de Rails + iPhone.

Imagen Thumbnail para rails_flisol_paraguana_2009.png En esta serie de 3 artículos, estaré haciendo un resumen de la demostración que realicé en el FLISOL Paraguaná 2009. Después de muchas vueltas, nunca logré ponerle un nombre bueno a la presentación, lo cual es algo que me decepciona. Mis amigos saben que me gusta ponerle nombres o títulos espaciales (si, con a no con e) a las cosas, por ejemplo, mi presentación del FLISOL pasado Entropía en el software, los cursos de Rails (Rails Sensei: Técnicas avanzadas y soluciones elegantes para la web). Pero en fin, aunque no fué el nombre que utilicé, vamos a conformarnos por ahora con Rails + iPhone.

No es usual en mí utilizar mucho texto en las presentaciones, pero si creen que les sirve de algo, o la quieren de recuerdo, pueden descargar la versión en pdf aquí.

Este primer artículo explicará lo que se desea hacer, se creará el proyecto y rápidamente generaremos un scaffold. La segunda parte consistirá en modificar un poco los estilos y ajustar el flujo de navegación, y la tercera parte consistirá en agregarle una interfaz para navegadores Mobile Safari (iPhone o iPod Touch).

Sé que muchos de los presentes ese día eran estudiantes, quizás no muy familiarizados con lo que es un Framework, con el patrón MVC, o con Ruby o Rails. La idea era demostrar lo rápido que era desarrollar una aplicación web con Rails y agregarle una interfaz específica para dispositivos móviles, en este caso un iPhone de Apple.

Después de una breve introducción, pudimos entrar en materia, crear la aplicación FLISOL To - do, una aplicación simple tipo to-do list. Así que entremos en materia nosotros también.

Una manera de definir lo que queremos hacer es diseñar la Interfaz Primero, preferiblemente con papel y lápiz (si, así de simple y barato) e ir planteando un flujo de la aplicación, por ejemplo: "hago clic aquí y se muestra tal cosa...", "clic en Aceptar para enviar los datos, luego se muestra el listado...". La idea es ir reflejando el flujo de trabajo del usuario con la aplicación. Este es el borrador de la interfaz para nuestro pequeño ejemplo.

Imagen Thumbnail para flisol_todo_borrador_interfaz.png Tenemos un título (Mis Tareas), que identifica toda nuestra interfaz, y claramente separamos las tareas Pendientes de las Finalizadas. Al hacer clic sobre un checkbox, indicamos si la tarea se terminó o la devolvemos al listado de pendientes. Adicionalmente incorporamos links para editar o eliminar cada una.

En la parte inferior se puede incorporar un formulario para agregar nuevas tareas. Se puede observar que la información asociada a una tarea incluye un Título y unas Notas. Por ejemplo:

  • Título: Escribir segunda parte del artículo de Rails + iPhone.
  • Notas: La segunda parte consta de aplicar los estilos y aplicar el flujo navegación detallado en la Parte 1.

Esto nos lleva al siguiente paso, definir un modelo inicial de datos para almacenar la información que deseamos mostrar. Al igual que antes, podemos usar lápiz y papel.

Imagen Thumbnail para flisol_todo_borrador_modelo.png Sin mucho análisis, un buen nombre para nuestro modelo sería Tarea (luego veremos que por convenciones de Rails, la tabla asociada a un modelo, por defecto es plural, por eso la imagen muestra tareas). Tanto título como notas son atributos que deben aparecer en este modelo, pero también debemos agregar un mecanismo para determinar si cada tarea ya fue finalizada. Un nombre ideal para este atributo sería finalizada de tipo boolean, que permita indicar con true o false si la tarea en cuestión ya se culminó. Un detalle adicional aquí es que el atributo finalizada debe ser por defecto false (En un to-do list, no tiene sentido crear una tarea ya finalizada).

Con las ideas claras y un bosquejo de lo que queremos hacer, lo siguiente es crear el proyecto en Rails y comenzar a darle forma para que se parezca a nuestros borradores.

Para crear el proyecto, escribimos en la línea de comando:

rails flisol_todolist
cd flisol_todolist

La primera línea utiliza la instrucción de línea de comando rails, la cual nos permite inicializar un proyecto, con todos los directorios básicos y archivos de configuración necesarios para desarrollar la aplicación. rails crea el directorio flisol_todolist, que contiene todo el proyecto. Con la segunda línea, simplemente ingresamos a este directorio.

Ahora, podemos dar un paso rápido y crear un scaffold o bien crear "a mano" un Controlador para procesar los requests, un Modelo para gestionar el acceso a datos y darle persitencia a la información y luego agregar cada una de las vistas que nos permitirán mostrar la información en el navegador. Nos iremos por el camino rápido y crearemos un scaffold, que hará por nosotros todo lo antes mencionado. Antes, vamos a recordar que dijimos que el nombre de nuestro modelo sería Tarea y que tenía los atributos titulo, notas y finalizada.

Nos vamos a una terminal (la misma que teníamos abierta) y dentro del directorio del proyecto (flisol_todo) ejecutamos:

script/generate scaffold Tarea \
  titulo:string \
  notas:text \
  finalizada:boolean

Lo que en realidad hicimos fue decirle al framework que generara un scaffold, es decir, una estructura base (de código fuente) de la cual podemos apoyarnos, para luego darle forma hasta convertirla en lo que realmente se ajusta a nuestras necesidades. Podemos notar que los argumentos son el nombre del modelo (Tarea en este caso) y sus atributos (los atributos son opcionales, pero en este ejemplo los incorporamos para yo no tener que escribir tanto en este artículo!!).

El Scaffold, aparte de crearnos el modelo Tarea (app/models/tarea.rb), el controlador TareasController (app/controllers/tareas_controller.rb) y las vistas principales (app/views/tareas), nos genera un migration, disponible en el directorio db/migrate/nnnn_create_tareas.rb (nnnn representa un timespamp). Por ahora vamos a conformarnos con saber que dicho migration nos permitirá especificar el esquema de la tabla asociada al modelo Tarea, es decir, el nombre de la tabla y sus columnas. Los migrations en Rails son extremadamente útiles, para mas información, pueden dirigirse a Rails Guides - Migrations. Vamos a darle una mirada a nuestro migration:

class CreateTareas < ActiveRecord::Migration
  def self.up
    create_table :tareas do |t|
      t.string :titulo
      t.text :notas
      t.boolean :finalizada

      t.timestamps
    end
  end

  def self.down
    drop_table :tareas
  end
end

Nos enfocaremos solamente en la sección create_table :tareas ... end. En criollo, dice lo siguiente (omitiendo t.timestamps):

Crea la tabla tareas, con el campo titulo de tipo string, el campo notas de tipo text y el campo finalizada como boolean.

Si comparamos eso, con la imagen de nuestro modelo, que discutimos anteriormente, vemos que falta sólo algo, el valor por defecto (default), que debe ser false, para lo cual sólo debemos agregar :default => false al campo finalizada. El migration luego de editarlo queda de la siguiente manera:

class CreateTareas < ActiveRecord::Migration
  def self.up
    create_table :tareas do |t|
      t.string :titulo
      t.text :notas
      t.boolean :finalizada, :default => false

      t.timestamps
    end
  end

  def self.down
    drop_table :tareas
  end
end

Antes de probar la aplicación, sólo nos queda crear la base de datos, la pregunta es ¿Si no hemos hablado si va a ser MySql, PostgreSql, SQLite, etc. Una ganancia de usar un framework (o mejor dicho un ORM) es tener la facilidad de hacer que nuestra aplicación sea en muchos casos database-agnostic, y Rails, o mejor dicho, ActiveRecord de Rails, es una de las cosas que nos permite hacer. Rails incluye una configuración de base de datos por defecto, la cual está basada en SQLite. Un extracto del archivo de configuración (config/database.yml) se muestra a continuación:

...
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000
...

Brevemente, adapter: sqlite3 indica que usaremos una base de datos SQLite 3.x y database: db/development.sqlite3 que está ubicada en el directorio db, con el nombre development.sqlite3.

Rails incluye un conjunto de tareas que nos permiten facilitar el trabajo con el (ejecutar rake -T para un listado), entre ellas la posibilidad de crear la base de datos y ejecutar los migrations de manera inteligente. Para crear la base de datos, con el esquema definido, ejecutamos en la terminal (si, en el directorio del proyecto) lo siguiente:

rake db:migrate

Listo! nuestra base de datos se creó en el directorio db, con el nombre development.sqlite3 (si no cambiaron el nombre y la ruta!!!). Si se genera algún tipo de error, revisar con tranquilidad los pasos anteriores, y todo el código escrito (:default => false jaja).

Para probar la aplicación, es necesario iniciar el servidor local, yo acostumbro abrir otra terminal (o pestaña) y utilizarla exclusivamente para el servidor de desarrollo, sólo recuerda verificar que estas en el directorio del proyecto. Para iniciar el servidor, ejecutar:

script/server

La salida indicará que el servidor inició y está escuchando en el puerto 3000, sólo nos queda disfrutar de la magia de Rails ingresando la url http://localhost:3000/tareas y jugar un poco agregando, modificando y eliminando tareas.

Si no probaron agregar una tarea con todos los campos en blanco, háganlo ahora, se darán cuenta de que no hay ninguna validación asociada. Como podrán imaginarse, el título debería ser requerido para cualquier tarea. Para lograr esto, editamos el archivo app/models/tarea.rb para que quede de la siguiente forma:

class Tarea < ActiveRecord::Base
  validates_presence_of :titulo
end

Si volvemos a intentar ingresar una tarea sin especificar un título, obtendremos un mensaje de error, indicándonos que el título no puede estar en blanco. Para mas información sobre las validaciones, pueden ingresar en Rails Guides - ActiveRecord Validations and Callbacks.

Con esto, finalizamos la primera parte de esta serie de 3 artículos, en la siguiente entrega, ajustaremos el flujo de navegación y los estilos para que parezca mas un to-do list y en la tercera, mostraremos las tareas en un iPhone, utilizando rails_jqtouch.

Saludos!

cartel_mugshots.jpg
El FLISOL Paraguaná 2009 finalizó con éxito, felicitaciones a todos los organizadores y participantes, incluyendo: GULIP, GULPF, VOSUG, Ubuntu-VE, y por supuesto nosotros como COTECSO. En su post, José Jimenez comenta varias de las actividades entorno a las instalaciones de GNU/Linux. Yo concuerdo con él respecto a que no fué tanta gente como el año pasado, pero los que fueron mostraron su entusiasmo e interés en las diversas actividades.

A la final, nosotros como COTECSO la pasamos muy bien, muchos de nuestros amigos y ex-compañeros de trabajo (antes de ser COTECSO) nos acompañaron, asistieron al evento y estuvieron un rato por nuestro stand apoyándonos. Tuvimos la oportunidad de ofrecer nuestros servicios de adiestramiento a los asistentes, entregamos folletos sobre nuestros cursos y dictamos varias charlas y/o demostraciones.

El evento comenzó como media hora después de lo planificado, las presentaciones tardaron un poco mas de lo esperado, por lo que vinimos terminando cerca de las 7pm (después de convencer a Alfonso que diera la charla de ilustración con Inkscape a pesar de la hora). Las charlas fueron las siguientes:

  • La realidad del software libre (Asdrúbal Colina - GULIP): Una charla introductoria a la filosofía del software libre, linux, etc. Esa siempre es una obligatoria en todos estos eventos.
  • CANAIMA GNU/Linux (Rodrigo Rodríguez - GULIP): Una muy buena reseña del trabajo que está realizando el equipo de desarrollo de la distribución nacional Canaima GNU/Linux, en la cual creo que él es tester. Mencionó la necesidad que tiene el proyecto de desarrolladores, e invitó a los asistentes a participar y hacer seguimiento de las actividades de Canaima GNU/Linux. ¿Quién sabe? de repente COTECSO se anima a participar en el proyecto...
  • Rails - Desarrollo de aplicaciones web con interfaces para dispositivos móviles (Ricardo Rodríguez --yo-- COTECSO): Más que una ponencia fué una demostración de Rails y como utilizarlo para desarrollar aplicaciones web con interfaces para diversos dispositivos, como por ejemplo un iPhone. Hablaré mas de ella en otro post.
  • Symfony - La evolución del programador en PHP (Sonalí Gutierrez - COTECSO): Una demostración en vivo, donde Sona contruyó una aplicación web con Symfony, para llevar el registro de los asistentes al FLISOL Paraguaná 2009.
  • Administrando contenido web con Joomla (Natasha Montero - COTECSO): Una demostración donde se le dió a conocer a los asistentas las bondades de Joomla para crear websites y portales, incluyendo el uso de plugins y módulos como el de encuestas (polls).
  • Linux en tiempo de crisis (Jorge Cobis - COTECSO): Cobis, con su amplia experiencia (incluyendo la docente), ofreció una interesante y graciosa presentación/demostración de como ahorrar con GNU/Linux y Multiterminales con Xorg. Como anécdota, Cobis quería llamarla Linux en tiempo de pelazón pero no lo dejaron!.
  • Exprésate con Wordpress (Angel Ferrer - COTECSO): Una demostración de como crear un blog con Wordpress y una invitación a los participantes a que creen su blog, así sea en cualquiera de los servicios de blogging gratuitos existentes en la internet.
  • Ilustración profesional con Inkscape (Alfonso Rodríguez): Aunque no fué representando ninguna Organización/Empresa/Grupo, fué invitado por COTECSO para que compartiera sus conocimientos sobre diseño gráfico e ilustración. Realizó una demostración muy amena sobre Inkscape y sus bondades, todos disfrutamos de sus impresionantes conocimientos en la materia.
En conclusión, todos salimos contentos del evento, y en general la pasamos muy bien, compartimos con viejos amigos y nos pusimos al día. Adicionalmente, hablamos con Alfonso para que formara parte de los autores de artículos de nuestro blog y comparta sus conocimientos a través de Tecnología Social.

Saludos!

      

Imagen Thumbnail para flisol_logo.png
Mañana 9 de Mayo es el FLISOL en Paraguaná, será en el Club Manaure, desde las 9 am hasta las 5 pm. Todos están invitados a asistir.

Nosotros como COTECSO estaremos participando como patrocinantes/organizadores, ayudaremos en las instalaciones de GNU/Linux, tendremos algunas demostraciones, incluyendo Linux, desarrollo de aplicaciones web con Rails, Symfony, websites y blogs con Joomla y Wordpress respectivamente (esperemos que de tiempo para todo eso...).

Hoy estuvimos al final de la tarde ayudando en la organización del salón, junto con GULIP. Algo de notar del salón es que tiene mucho eco (bueno, quizás con todas las personas dentro no se sienta) y hay muy pocos tomacorrientes, así que hay que llevarse todas las extensiones posibles para el día de mañana.

Yo por mi parte, dictaré una demostración de dearrollo web con Rails y cómo agregar interfaces para dispositivos móviles, en este caso, para un iPhone. Mostraré, con el poco tiempo que tenemos disponible para la presentación, un poco de mi plugin de Rails rails_jqtouch, del cual escribiré pronto para hacerlo conocer y agregar algunos ejemplo de uso.

Bueno, en fin, nos vemos mañana!!!
bienvenidos.jpgBienvenidos al blog Tecnología Social. Este blog es mantenido por el personal de la Asociación Cooperativa Tecnología Social, mejor conocidos como COTECSO. Después de un tiempo bastante largo de conformación de nuestra cooperativa, después de muchos papeleos, inconvenientes y burocracia, pero siempre con muchas ganas de salir adelante, estamos aquí, organizados, trabajando y comenzando a compartir conocimiento con la comunidad.

En Tecnología Social, estaremos escribiendo constantemente (espero), sobre lo que hacemos. Encontrarás referencias a noticias, así como tutoriales, artículos e información valiosa sobre GNU/Linux, Ruby, Rails, PHP, Symfony, desarrollo web en general, Patrones de Diseño, AJAX, Javascript, CSS y pare de contar.

Esperamos que Tecnología Social les sea de su mas completo agrado, manténganse en sintonía, que estaremos publicando varios artículos pronto. Ésta es una semana importante para nosotros, es el FLISOL en Punto Fijo, donde somos patrocinantes, organizadores, ponentes, etc.

De más está decirles que, cualquier comentario para mejorar nuestro blog será apreciado.

Así que, ¡BIENVENIDOS!

Sobre COTECSO

Somos un equipo pragmático, desarrollamos software de manera ágil y elegante, nos gusta la tecnología, la simplicidad y las cosas bien hechas.

Comentarios recientes

Cerrar