Archivo para la categoría Ruby on Rails

October 8th, 2009 por CaDs

Cualquiera que haya programado en Rails conocerá algo de YAML ya que se usa, entre muchas otras cosas, para la configuración de la base de datos.

YAML en breve, es un lenguaje para la serialización de datos bastante fácil de entender y cómodo de usar (podéis ver ejemplos aquí).

No sería genial poder definir nuestros archivos de configuración usando YAML como los properties en Java?

Pues es muy sencillo.

Paso1: Crear el archivo de configuración dentro de la carpeta /config. Para este ejemplo yo he creado un archivo llamado config.yml con el siguiente contenido:

/config/config.yml


:attribute1:
  :param1: my config stuff
  :param2: more config stuff
  :param3: yet another param

:attribute2:
  :param1: more config 
  :param2: blahblahbla
  :param3: another thing

Paso 2: Cargar el archivo de configuración al levantar nuestra app. Para ello crearemos un inicializador dentro de la carpeta /initializers.
En mi caso yo he creado un archivo llamado config_loader.rb con el siguiente contenido:

/initializers/config_loader.rb


config_file = File.read(RAILS_ROOT + "/config/config.yml")
CONFIG = YAML.load(config_file)

Y eso es todo, tras reiniciar vuestra aplicación podréis acceder a vuestros parámetros dentro de vuestro código llamándolos con: CONFIG[:attribute1][:param1]

Enjoy! :)

  • Share/Bookmark
August 6th, 2009 por CaDs

Instalar Ruby y Rails en general suele ser un proceso sencillo e indoloro, pero instalar el mysql gem de vez en cuando da algún que otro dolor de cabeza.
En concreto si usan Leopard tras instalar/actualizar correctamente ruby y rails (que vienen por defecto en el sistema) al hacer el clásico sudo gem install mysql nos dará un bonito error.

La solución a esto es modificar el comando ligeramente para pasarle algunos parámetros adicionales. De manera que quede algo así:

sudo env ARCHFLAGS=”-arch i386″ gem install mysql — –with-mysql-config=/path/to/mysql_config

Siendo /path/to/mysql_config la ruta donde resida la configuración de vuestro mysql (por defecto/usr/local/mysql/bin/mysql_config )

Enjoy!

  • Share/Bookmark
December 12th, 2008 por CaDs

Hacer una búsqueda dinámica para que vayan apareciendo los resultados a medida que escribimos en el formulario es relativamente sencillo con rails.
Para ello sólo necesitamos los siguientes elementos:
Primero de todo necesitamos cargar los elementos ‘ajaxianos’ que vienen con rails. Para ello basta con incluir:


<%=  javascript_include_tag :defauts %>

Generalmente es una buena práctica incluir este tag en el layout general, pero eso depende de cada uno.

Vista:


<% form_tag 'search' do %>  
<div class="table_title">
    <table>
      <tr>
        <td>Buscar:</td>
        <td><%= text_field_tag("query", params[:query], :autocomplete => "off" ) %></td>
      </tr>
    </table>
      
</div>
<% end %>
    
    <%= observe_field 'query',  :frequency => 2,
                        :update => search_results",                
                :url => {:controller => "friends", :action => "search"},
                 :with => "query" %>

<div id="search_results">
</div>

Con esto definimos un campo de búsqueda llamado query donde iremos haciendo las búsquedas.
Adicionalmente con observe_field indicamos que debemos realizar cada cierto tiempo una búsqueda con los parámetros de query usando la acción search del controlador friends.
Y también definimos un div llamado search_results, inicialmente vacío, que será actualizado con los resultados de esa búsqueda.

Controller:


def search    
    session[:query] = params[:query].strip if params[:query]

    if session[:query] and request.xhr?
      @friends = Friend.all(:conditions => ["first_name LIKE ?", "%#{session[:query]}%"], :order => "first_name ASC")     
      render :partial => "search_results", :layout => false, :locals => {:searchresults => @friends} 
    end
  end

Donde hacemos una búsqueda con los parámetros que hemos obtenido desde nuestra vista y la presentamos en un partial llamado search_results pasándole los resultados de la búsqueda.
El código de este partial puede ser a gusto de cada uno, simplemente debe presentar los resultados.
Un ejemplo sería:


<% if searchresults.length == 0 %>
        <p>No se han encontrado resultados</p>
<% elsif params[:query] == "" %>
        <p>No hay términos de búsqueda</p>
<% else %>
<div class ="search_results">
  <strong>Amigos Encontrados:</strong>
  <table>
  <% for friend in searchresults %>     
    <tr>
      <td>
              <%=friend.last_name%>, <%=friend.first_name%>  
      </td>
    </tr>
  <% end %>
  </table>
</div>
<% end %>

Modelo:
Un modelo básico que nos serviría para este ejemplo sería algo así.


class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table (:friends,:options => 'DEFAULT CHARSET=UTF8') do |t|
      t.column :first_name, :string
      t.column :last_name, :string
      t.timestamps
    end
  end

  def self.down
    drop_table :friends
  end
end


Y eso sería todo, ya tenemos una búsqueda dinámica en menos de 5 minutos.

Enjoy

  • Share/Bookmark
December 10th, 2008 por CaDs

En general Test suele ser sinónimo de aburrimiento, al menos en lo que a la opinión popular se refiere. Conozco pocos programadores que realmente disfruten escribiendo tests o que lo hagan sin una petición explícita ya sea por parte de sus jefes, el departamento de calidad… etc.

En general creo que existe el concepto de que uno programa su código y debe haber otra persona que se encargue de hacer el testing y reportarnos los bugs.
Si bien el concepto de Test y QA (Quality Assurance) están relacionados, lo uno no debiera reemplazar a lo otro.

Sobre si se debe escribir tests o no, o qué técnica es la verdadera y única (TDD, BDD, ?DD….) se han escrito infinidad de páginas, y la verdad no me interesa entrar en polémicas, así que os voy a explicar desde mi punto de vista por qué usar tests es conveniente para cualquier programador.

Un test se podría definir como una inversión a largo plazo, es cierto que inicialmente consume parte del tiempo (que como programadores estamos deseando invertir en desarrollar nuestra lógica y hacer una bonita interfaz) pero a lo largo de la vida del proyecto uno disfruta de los beneficios.

Pero dejémonos de rodeos y teoría, vamos a entrar en materia

Para este ejemplo usaré rspec, un framework de testing para Ruby on Rails.
Sus creadores lo definen como un BDD (Behavior Driven Development) framework para ruby, y sin entrar en mayores detalles sobre lo que representa el BDD diré que la filosofía detrás de esta metodología de testing consiste en centrarnos más en el cómo debe comportarse nuestra aplicación sin necesidad de preocuparnos de los detalles de implementación.

Toda esta parafernalia técnica está muy bien, pero para mí simplemente significa que escribir tests deja de ser una tarea aburrida y pasan a formar parte fundamental del código y sobre todo de la documentación.
Y esto es importante Test = Documentación, porque cuando podemos presentar nuestros tests como la documentación fiable y actualizada de nuestro código estamos matando dos pájaros de un tiro (y nos ahorramos la pesada tarea de hacer esos documentos en word con screenshots y frases cortas del tipo “X hace Y”.

Nota: He usado rspec como ejemplo y como framework para mis proyectos porque me gusta, eso no quiere decir que no podamos obtener los mismos resultados usando otros framework de testing.
Ejemplos perfectamente válidos son JUnit, RUnit, PyUnit, PHPUnit … y un largo etcétera. Prácticamente cualquier lenguaje de programación dispone de varios frameworks para testing que podréis usar según vuestras preferencias.
Igualmente da lo mismo qué filosofía de testing decidáis usar, TDD, BDD, WhateverDD, un test simplemente consiste en tener la seguridad de que independientemente de los cambios que se hagan en el código en las diversas refactorizaciones o ampliaciones del mismo, lo que funcionaba antes sigue funcionando.

Hechas las aclaraciones pertinentes…

Instalar rspec es relativamente sencillo, instalamos el gem:

[sudo] gem install rspec-rails

Y en nuestra aplicación corremos el script:

ruby script/generate rspec

Este script nos creará una nueva carpeta en nuestro proyecto llamada spec…

… con varias subcarpetas.
Para los que estéis acostumbrados a Rails y a MVC en general veréis que existe una carpeta para los controladores, otra para los modelos y otra para las vistas. Estas carpetas contendrán los tests (o specs) que escribiremos para cada uno de esos elementos.
Adicionalmente tenemos la carpeta de helpers donde podremos escribir funciones auxiliares que vayamos a usar en nuestos tests y la carpeta de fixtures, donde podemos definir algo así como los mock objects que usaremos.

Bien, cómo creamos un test? Fácil. Rspec pone a nuestra disposición varios scripts que podemos usar integrados con Rails.
Por ejemplo, al crear un controlador habitualmente escribimos el comando:

./script/generate controller user

(siendo user un nombre cualquiera)

Bien, rspec nos permite hacer lo mismo pero con un sutil cambio:

./script/generate rspec_controller user

Este comando, además de generar nuestro habitual /app/controllers/user_controller.rb


class UserController < ApplicationController
end

creará un archivo en la carpeta /spec/controllers llamado user_controller_spec.rb donde podremos escribir nuestros specs.


require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe UserController do

  #Delete this example and add some real ones
  it "should use UserController" do
    controller.should be_an_instance_of(UserController)
  end

end

Qué contiene este archivo? primero carga el spec_helper para hacer disponibles las funciones auxiliares que hayamos definido y por otro lado comienza a describir nuestro controlador con el comando describe.

Describe sigue la habitual estructura de bloques de RoR conformando un bloque…


describe UserController do
#Specs varios...
end

…donde comenzaremos a definir qué queremos que haga nuestro controlador.
Rspec nos genera un ejemplo (que borraremos en breve) que si bien no nos aporta gran cosa, sí nos da una pequeña idea de como escribir nuestros specs:


it "should descriptión de la acción" do
#Comportamiento deseado
end

En este punto estamos preparados para comenzar a codificar.
Los puristas del TDD dicen que “todo comienza con un test que falla”. Así que siguiendo este consejo vamos a escribir nuestro primer test sin haber escrito todavía una sola línea de código.
Borramos el test que nos viene por defecto y escribimos nuestro primer test, algo básico que nos sirva como ejemplo podría ser:


require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe UserController do

  it "should render the register page" do
    get :register
    response.should render_template 'register'
  end

end


Este sencillo spec puede entenderlo cualquier persona, aun sin conocer nada de programación (vale, esa persona debe conocer algo de inglés) y nos sirve para definir el comportamiento que deseamos para nuestra aplicación.

En este caso es trivial, estamos accediendo con un método get a la acción register y esperamos que la respuesta muestre la página de registro dentro del controlador de usuarios.
Así que en cierto modo estamos definiendo para nuestra aplicación el comportamiento de un usuario. Si un usuario hace click en el link de registrar nuestra aplicación navegará a la página de registro donde el usuario puede meter sus datos y registrarse.

Así pues hemos escrito nuestro primer test y estamos listos para ver si funciona.
Para ello rspec nos proporciona algunos scripts que podemos usar:

./script/spec path/to/directory/with/specs

correrá todos los spec que existan en un determinado directorio, y

./script/spec path/to/individual_spec.rb

correrá un determinado spec.

En nuestro caso escribiremos:

./script/spec spec/controllers/user_controller_spec.rb 

Y la respuesta que obtendremos probablemente será algo como:
ActionController::UnknownAction in ‘UserController should render the register page’
No action responded to register. Actions:
…..
Finished in 0.097963 seconds

1 example, 1 failure

Tenemos nuestro primer fallo!, así que según los puristas del TDD vamos por el buen camino.
Por lo que leemos al parecer se está quejando de que no reconoce una acción llamada register, así que vamos a definirla.


def register
#Código para registrar un usuario, vacío por el momento    
end

Volvemos a correr nuestro test

./script/spec spec/controllers/user_controller_spec.rb 

y ahora la respuesta debiera ser algo como:
Finished in 0.223996 seconds

1 example, 0 failures

Funciona!, a partir de ahora hemos definido que al acceder a la acción registrar usuarios siempre debemos presentar la página de registro.

Este ejemplo, aunque parezca trivial y una tontería, nos sirve para definir cómo trabajar con tests.
Comenzamos escribiendo algunas especificaciones para nuestro código y luego nos aseguramos de que el código cumpla con lo definido.

Por qué no al revés? Por qué no escribir primero el código y luego los test?
Hay diversas razones que nos animan a hacerlo de esta manera.

    Por un lado en muchas ocasiones tenemos ideas, ya sean propias o de nuestros clientes, que se desean incorporar a un proyecto. Estas ideas, requisitos, funcionalidades, etc… especificaciones a fin de cuentas (o specs para abreviar) definen el comportamiento de la aplicación y deben ser escritas independientemente de la implementación que se vaya a realizar posteriormente. (otra cosa es poder hacerlo o no, pero eso no nos importa en este momento)
    Codificando inicialmente y posteriormente escribiendo los tests de alguna manera estamos imponiendo nuestra implementación sobre la especificación, pudiendo llegar a “corromperla” en cierto modo.
    Por otro lado en ocasiones simplemente deseamos anotar cosas que deseamos que nuestra aplicación haga, sin tiempo para ponernos a codificar. Tal vez estemos redactando un documento de especificación y deseamos presentar lo que hace nuestra aplicación y obtener el feedback de nuestro cliente antes de emplear recursos.

En fin, las razones son varias. No me considero un evangelista, de esos hay muchos por ahí pululando. Si os interesa realmente el tema buscad sobre TDD o BDD en google y probablemente encontréis más de lo que podáis digerir.

Siguiendo con nuestro ejemplo, alguien podría decir que el test es un poco ciego. Estamos esperando que se presente la página de registro pero en realidad no tenemos página de registro y sin embargo el test funciona.
Esto nos lleva a dos conceptos interesantes.

    Convention over configuration: Rails sabe que debe existir un template con el mismo nombre que la acción que define, así que siguiendo la convención, rspec sabe que en algún momento debe existir un template con ese nombre, así que no se preocupa de si está presente o no.
    Rspec es flexible: La cantidad de opciones que nos permite rspec es abrumadora, de hecho es una de las causas por las que tiene una curva de aprendizaje no tan suave como a muchos nos gustaría. Sus programadores tuvieron en cuenta las diversas capas del MVC a la hora del diseño y por tanto permite la abstracción en cuanto a la capa de presentación.

No obstante si ninguna de estos conceptos te convence, no hay problema, podemos usar un comando para que rspec integre las restricciones de las vistas dentro de los tests de nuestro controlador, basta con escribir integrate_views.


require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe UserController do
  integrate_views
  
  it "should render the register page" do
    get :register
    response.should render_template 'register'
  end

end


Si volvemos a correr nuestro test ahora debieramos obtener algo como:

1)
ActionView::MissingTemplate in ‘UserController should render the register page’
Missing template user/register.erb in view path /Users/cads/post/app/views:
….
Finished in 0.101716 seconds

1 example, 1 failure

Ahora efectivamente se queja de que le falta la página de registro, así que debemos proporcionársela para que se quede contento.
Un ejemplo rápido podría ser:
app/views/user/register.html.erb


<div id="title">
  <h2>User Registration Page</h2>
</div>
<div id="form_fields">
  Username: <%= text_field_tag 'user_name', nil, :size => 20 %>
  <br/>
  Password: <%= password_field_tag 'password', nil, :size => 20 %>
</div>
<div id="buttons">
  <%= submit_tag "Register" %>
</div>

Si corremos ahora nuestro spec vemos que ya está contento:

Finished in 0.096693 seconds

1 example, 0 failures

Rspec proporciona una potente herramienta para testear interfaces, permitiéndonos validar incluso la existencia de tags en las vistas.


it "should render the register page" do
    get :register
    response.should render_template 'register'
    #Vamos a checkear que existan los 3 divs principales
    response.should have_tag("div[id=title]")
    response.should have_tag("div[id=form_fields]")
    response.should have_tag("div[id=buttons]")
end

Pero esto nos desvía, para más información sobre rspec podéis visitar su página de documentación (buena suerte)

El si se debe incluir la validación de interfaces dentro de los tests de un controlador es motivo de polémica y discusiones.
Podemos crear specs asociados a vistas y dedicarnos por completo a testear cada una de las vistas de nuestra aplicación.
Para ello bastaría con crear el archivo spec/views/user/template_spec.rb con un formato similar al anterior.

Nota: Si al generar nuestro rspec_controller indicamos las acciones del controlador rspec generará automáticamente specs para cada una de las vistas asociadas a las acciones.
Así pues, si hubiéramos generado nuestro user_controller de esta manera:

./script/generate rspec_controller user register

rspec habría generado: spec/views/user/register.html.erb_spec.rb


describe "/user/register do
  before(:each) do
    render 'user/register'
  end
  
  #Delete this example and add some real ones or delete this file
  it "should tell you where to find the file" do
    response.should have_tag('p', %r[Find me in app/views/user/register])
  end
end

Pero como digo, no quiero complicaros la existencia con las ramificaciones de rspec.

Retomando nuestro spec, vamos a generar otra descripción no tan trivial:


it "should register a user" do
    post :register, :user => {:user_name => 'Anakin', :password => 'yoda'}
    #Si lo ha creado bien debe redireccionarnos a la pagina del profile
    response.should redirect_to :action => 'profile'
    #El usuario Anakin debe existir y estar almacenado en nuesta base de datos
    User.find_by_user_name('Anakin').should_not be_nil
end

Ahora tenemos dos specs que podemos correr, con el resultado:

.F

1)
‘UserController should register a user’ FAILED
expected redirect to {:action=>”profile”}, got no redirect
./spec/controllers/user_controller_spec.rb:18:
./script/spec:5:

Finished in 0.099972 seconds

2 examples, 1 failure

Nuevamente tenemos un test que falla, y tenemos una nueva funcionalidad y comportamiento que nos interesa, así que ahora podemos implementarla:


class UserController < ApplicationController
  
  def register
    #Registrará un usuario
    if request.post? and params[:user]
      user = User.new(params[:user])
      if user.save
        redirect_to :action => 'profile'
      end
    end
  end
  
  def profile
    #Traerá el perfil del usuario
  end
  
end


Ahora el código debiera cumplir con lo que pide el test, así que volvemos a correr nuestro spec y…

.F

1)
NameError in ‘UserController should register a user’
uninitialized constant UserController::User
….
Finished in 0.102123 seconds

2 examples, 1 failure

Cierto! se nos había olvidado crear el modelo User.

Como vemos, a partir de un simple test vamos dando forma a nuestra aplicación, escribiendo código que cubra las necesidades de nuestras especificaciones y asegurándonos de esta manera que todo funcione según lo definido.
Así pues generamos nuestro modelo:

./script/generate rspec_model user

Definimos los atributos:
db/migrate/create_users.rb


class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.column :user_name, :string
      t.column :password, :string
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end

migramos


rake db:migrate

y


rake db:test:prepare

y volvemos a correr nuestro spec:

..

Finished in 0.109147 seconds

2 examples, 0 failures

Y listo, nuevamente todo funciona nuevamente.

Si os habéis fijado a la hora de generar el modelo he usado un rspec_model.
Al igual que con los controladores y las vistas, rspec nos permite crear tests para nuestros modelos y al igual que antes podemos encontrar el spec generado en spec/models/user_spec.rb


require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe User do
  before(:each) do
    @valid_attributes = {
    }
  end

  it "should create a new instance given valid attributes" do
    User.create!(@valid_attributes)
  end
end

El cual, incialmente es trivial como el resto de sus compañeros, pero nos permite validar el correcto comportamiento de los modelos.
Por ejemplo si quisieramos asegurarnos de que debe existir un user_name y un password para nuestro modelo user podemos escribir:


class User < ActiveRecord::Base
  validates_presence_of :user_name, :password
end

Lo cual nos asegura de que nuestros usuarios para ser válidos deben tener un nombre de usuario y un password.
Si corremos ahora nuestro user_spec.rb debiera fallar:

./script/spec spec/models/user_spec.rb
F

1)
ActiveRecord::RecordInvalid in ‘User should create a new instance given valid attributes’
Validation failed: Password can’t be blank, User name can’t be blank

Finished in 0.158742 seconds

1 example, 1 failure

Ahora requerimos que nuestros usuarios tengan ciertos atributos, asi que podemos requerirlos en el test y validar que todo siga correctamente.
Para ello basta con definir dentro de @valid_attributes los atributos que requiramos como obligatorios:


require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe User do
  before(:each) do
    @valid_attributes = { :user_name => 'Sheldom', :password => 'Leonard'
    }
  end

  it "should create a new instance given valid attributes" do
    User.create!(@valid_attributes)
  end
end

Si ahora volvemos a correr nuestro test veremos que…

.

Finished in 0.1016 seconds

1 example, 0 failures

Todo vuelve a funcionar.

Con esto termino este laaargo post.
La idea es que partiendo de tests podemos desarrollar el resto de la aplicación de una manera ordenada y con la seguridad de que si en el futuro, debemos refactorizar nuestro código (algo bastante habitual) y teniendo tests no “contaminados” con los detalles de la implementación, podemos estar relativamente seguros de que todo está bien sin tener que volver a navegar manualmente por todas y cada una de las funcionalidades de nuestra aplicación.

Nota: Correr los tests a mano cada vez que uno hace un cambio es bastante pesado y cansino, así que hay diversas herramientas que se encargan de hacerlo por nosotros.
Yo en concreto uso rspactor que se encarga de correr automáticamente los specs relacionados cada vez que se guardo un cambio en algun archivo y genera notificaciones con growl.
Para los que no uséis mac sé que hay versiones similares que corren en windows o en linux, pero ahora mismo no tengo el enlace por aquí.

Enjoy

  • Share/Bookmark
November 17th, 2008 por Jorge Yau

Hay varias formas de publicar tus aplicaciones en un ambiente de producción, esto se te puede complicar si vienes de un ambiente de PHP y Apache, estas acostumbrado a solo crear un Virtual Host apuntando a un directorio donde tienes todos los archivos de la aplicación.

Con Ruby on Rails la cosa es un poco más complicada, existes diversas opciones para remplazar Apache como tu servidor web, mi recomendación es usar Nginx+mongrel, el cual es un servidor que usa una décima parte de los recursos que normalmente Apache utiliza, el proceso es más complicado y requiere de un nivel mas alto de conocimiento sobre el funcionamiento de servidores, recursos, etc.

A continuación, la forma más rápida y sencilla de publicar una aplicación en un ambiente de producción.

Necesitas contar con Apache2, si no lo tienes instalado solo escribe lo siguiente en tu línea de comando:

$ sudo apt-get install apache2 apache2.2-common apache2-mpm-prefork apache2-prefork-dev apache2-utils libexpat1 ssl-cert libapr1 libaprutil1 libmagic1 libpcre3 libpq5 openssl

Luego de tener Apache2 procede a installar Passenger con el siguiente comando:

$ sudo gem install passenger
$ passenger-install-apache2-module

Luego solo es cosa de configurar un nuevo Virtual Host en la configuración de tu Apache, ya sea en httpd.conf o como un sitio en /etc/apache2/sites-enabled/, de la misma forma en la que configuras un sitio normal.

<VirtualHost *:80>
    ServerName www.tudominio.com
    DocumentRoot /var/www/tuaplicacion/public
</VirtualHost>

Una vez configurado, reinicia tu Apache, y podrás ver tu aplicación en www.tudominio.com

Si requieres más información, visita el sitio de Passenger y lee la documentación

  • Share/Bookmark
November 17th, 2008 por CaDs

Buscando sitios para hostear mis aplicaciones me he dado cuenta de que en algunos sitios ofrecen una imagen de Ubuntu para administrar como deseemos y en el caso de querer que nos dejen pre-instalado ruby y rails cobran un dinero adicional.
Curiosamente instalar Ruby y Rails en una Instalación de Ubuntu en blanco es relativamente sencillo así que les vamos a ahorrar algunos dólares.

1. Instalamos Ruby:

sudo apt-get install ruby-full build-essential

2.Instalamos Ruby Gems:

wget http://rubyforge.org/frs/download.php/38646/rubygems-1.2.0.tgz
tar xzvf rubygems-1.2.0.tgz
cd rubygems-1.2.0
sudo ruby setup.rb
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem
sudo gem update --system

3. Teniendo Gems Instalado podemos usarlas para Instalar Rails…

sudo gem install rails

4. … y Mongrel:

sudo gem install mongrel

Listo, ya tenéis la base para correr vuestras aplicaciones RoR en una nueva Instalación de Ubuntu :)

  • Share/Bookmark
November 3rd, 2008 por CaDs

La idea detrás de la metodología MVC (Modelo Vista Controlador) consiste en separar en 3 capas independientes, pero interconectadas entre sí aspectos comunes a cualquier aplicación web.
De este modo tenemos las siguientes capas:

  • Modelo:Se encarga de encapsular la entidad que queremos representar y persistirla en memoria de alguna manera (habitualmente una base de datos).
  • Vista:Se encarga de proporcionar al usuario una interfaz para visualizar e introducir información.
  • Controlador:Contiene la lógica que se usará para administrar la información que circulará por el sistema. Es decir, se encargará de realizar las operaciones necesarias para proporcionar información de salida o se encagará de administrar la información que el usuario haya introducido.

La idea detrás de esto es mantener estos tres aspectos de cualquier aplicación independientes entre sí, de manera que un diseñador web pueda trabajar en la interfaz de nuestra aplicación mientras que un equipo de programadores desarrollan la lógica y tal vez un administrador de bases de datos define la mejor manera de almacenar nuestros objetos.

Hasta aquí a teoría, vayamos a la práctica. (Este ejemplo supone que tienes Ruby y Rails instalados)
Rails incorpora esta metodología como parte de su diseño, de manera que trabajando con Rails automáticamente estamos usando MVC.
Comencemos creando un nuevo proyecto de Rails. Abrimos una terminal nueva e introducimos:
rails bookstore
Esto nos generará el esqueleto de una aplicación Rails lista para trabajar.
Ahora para generar nuestros componentes basta con entrar al nuevo directorio que Rails ha creado:
cd bookstore
y escribir el siguiente comando:
./script/generate model book
o
ruby script/generate model book
Según la plataforma que uses y rails se encargará de crear varios archivos:

exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/book.rb
create test/unit/book_test.rb
create test/fixtures/books.yml
create db/migrate
create db/migrate/20081103140957_create_books.rb

En concreto nos interesan los dos archivos resaltados: book.rb y 20081103140957_create_books.rb
Si abrimos con cualquier editor book.rb veremos algo así:


class Book < ActiveRecord::Base
end

Esta aparentemente inofensiva clase incorpora un montón de funciones encapsuladas dentro de ActiveRecord::Base que importa todas las funciones de la clase ActiveRecord.
Dentro de esta clase incorporaremos todas las restricciones y lógica aplicada al modelo, de manera que podemos diseñar independientemente nuestro modelo.

El otro archivo que nos interesa 20081103140957_create_books.rb veremos algo así:


class CreateBooks < ActiveRecord::Migration
  def self.up
    create_table :books do |t|

      t.timestamps
    end
  end

  def self.down
    drop_table :books
  end
end

Donde podemos definir las columnas que formarán parte del objeto que persistiremos en nuestra base de datos. Ej:

 create_table :books do |t|
      t.column :title, :string
      t.column :ISBN, :string
      t.column :author, :string 
      t.timestamps
    end

Con esto tenemos nuestros modelos perfectamente controlados y listos para trabajar.

Ahora, si queremos generar un controlador basta con introducir el siguiente comando en nuestra terminal:
./script/generate controller bookstore

Lo cual al igual que antes, nos generará algunos archivos:

exists app/controllers/
exists app/helpers/
create app/views/bookstore
exists test/functional/
create app/controllers/bookstore_controller.rb
create test/functional/bookstore_controller_test.rb
create app/helpers/bookstore_helper.rb

Como antes el archivo que nos interesa es el llamado bookstore_controller.rb


class BookstoreController < ApplicationController
end

Al igual que antes vemos que esta clase, aparentemente vacía hereda de ApplicationController, lo cual nos permite hace bastantes cosas, entre ellas definir código que va a controlar las vistas que vamos a generar.
Por ejemplo podemos escribir algo como:


class BookstoreController < ApplicationController
  
  def index
    #Codigo para la página bookstore/index.html.erb
  end
  
  def add
    #Codigo para la pagina bookstore/add.html.erb
  end
  
  def remove
    #Codigo para la pagina bookstore/remove.html.erb
  end
  
end

Como podéis ver, los métodos que definimos dentro del controlador tienen efecto sobre ciertas páginas. La idea que hay tras ruby on rails es que este framework se encarga de realizar “todo el cableado interno” entre el controlador y las vistas.

Si nos fijamos en la estructuras de carpetas que nos generó el comando rails vemos que existe la siguiente estructura:

app/view/bookstore

Como vemos Rails nos genera una carpeta para almacenar las vistas asociadas al controlador que hemos creado (bookstore), de manera que podemos crear los archivos que serán nuestras vistas dentro de cada carpeta asociada a un controlador. Ej: index.hml.erb


<p> Hola, esta es la vista para la acción Index </p>

Importante, el nombre de la página debe llamarse igual que el nombre de la acción en el controlador.
Ej. Para el método index, debe existir el archivo index.html.erb, para el método add debe existir el archivo add.html.erb y así sucesivamente.

Si os habéis perdido en estos pasos lo mejor que podéis hacer es jugar un poco con vuestra aplicación de Rails.
Para ello arrancad vuestra aplicación con el siguiente comando:
./script/server
E introducid la siguiente dirección en vuestro browser:
http://localhost:3000/bookstore/index
Si todo ha ido bien debierais ver el texto:

Hola, esta es la vista para la acción Index

Como podemos ver las rutas en rails son bastante simples de entender:
Host/Controller/Action

Listo, ya tenéis una pequeña aplicación usando la metodología MVC. Cierto que no hace gran cosa, pero es un buen punto de partida :)

  • Share/Bookmark
October 26th, 2008 por Jorge Yau

El concepto es sencillo, Hoptoad se encarga de recibir todos los mensajes de error que genere tu aplicación, Hoptoad se encargará de archivarlos y enviarte un reporte, incluso detecta si es un error duplicado y evita enviártelo múltiples veces.

Para esto solo necesitas:

  1. Crear una cuenta gratiuta y Crea tu primer proyecto
  2. Instala el plugin
    script/plugin install git://github.com/thoughtbot/hoptoad_notifier.git
  3. Configura tu aplicación

    Crea un initializer llamado hoptoad.rb en config/initializers/hoptoad.rb y copia lo siguiente:

    
    HoptoadNotifier.configure do |config|
      config.api_key = 'TU API KEY'
    end
    

    Luego añade lo siguiente a tu application controller:

    include HoptoadNotifier::Catcher

Y eso es todo, los errores de tu aplicación serán enviados directamente a tu e-mail.

  • Share/Bookmark
October 20th, 2008 por CaDs

Decidir si tu aplicación debe usar UTF-8 encoding es una duda que tarde o temprano asalta a cualquier programador.

Los factores que pueden influir en la decisión de usar o no este tipo de encoding pueden variar, pero en general depende de en dónde vayan a estar localizados los usuarios de tu aplicación.
En el caso de una aplicación web destinado al gran público en general es recomendado habilitar este tipo de encoding para que todo el mundo pueda leer o escribir en cualquier idioma usando cualquier tipografía.
Se podría escribir un libro sobre encoding (de hecho hay bastantes escritos sobre el tema) pero no es el punto de este post.

Supongamos que has decidido construir una aplicación web que revolucionará el mundo y quieres que cualquiera pueda usarla, y has decidido usar Rails para ello (sabia decisión :P ) he aquí los pasos a seguir.

Primero debes indicar a tu browser que tipo de encoding debe interpretar. Para eso basta con insertar un simple tag en la cabezara de tus páginas:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Usar un layout general para toda tu aplicación es en general una manera simple y DRY de hacerlo.

Ahora, suponiendo que tu aplicación use un mecanismo de persistencia (algo bastante habitual) y suponiendo que dicho mecanismo sea una base de datos (bastante habitual tambien) Rails nos permite definir el encoding para nuestra aplicación de una manera bastante simple.
Este ejemplo muestra la configuración para una base de datos mysql.
database.yml:

development:
    adapter: mysql
    database: myapp
    user: root
    host: localhost
    encoding: utf8

Con esto indicamos el encoding para la base de datos, sin embargo en ocasiones y dependiendo de la versión, hay veces que es necesario indicar el encoding de las tablas, las cuales por defecto usan LATIN1.
Para ello basta con agregar en cada migración lo siguiente:
create_users.rb:


   def self.up
    create_table (:users,:options => 'DEFAULT CHARSET=UTF8') do |t|
       ...
   end

Y eso es todo ;)

  • Share/Bookmark
October 18th, 2008 por Jorge Yau

Hace un par de días decidí añadirle la opción de poder publicar anotaciones vía e-mail a una de las aplicaciones en las que estoy trabajando, una opción es tener un proceso automatizado que revise una cuenta de correo cada cierta cantidad de tiempo y luego procesar cualquier correo entrante, la desventaja de esto, es que le estas añadiendo procesos innecesarios a tu servidor, ya que para que funcione en tiempo real, debes revisar la cuenta en un corto intervalo de tiempo, el cual utiliza recursos de tu servidor haya o no mensajes nuevos, hay otras formas, mas complejas que requieren mucha configuración y acceso directo a un servidor SMTP, pero esto no es lo que estaba buscando, lo que necesitaba era una forma rápida y sencilla de procesar correos entrantes de múltiples direcciones de correo, sin sobrecargar mi servidor.

Decidí buscar una alternativa hospedada fuera de mi servidor y que fuera fácil de utilizar sin un alto costo, encontré dos opciones Mailhook.org ($14/año) y smtp2web (gratis), el concepto de ambos, es que se encargan de recibir tu correo, y al recibirlo es reenviado a tu aplicación en forma de POST, este POST incluye todo el mensaje incluyendo ‘headers’ y archivos adjuntos, para ser procesados en tu aplicación de la forma que te plazca. De esta forma tu servidor solo entra en acción cuando un e-mail es recibido.

La decisión no fue muy difícil viendo que ambos servicios son similares, decidí darle una oportunidad a la versión gratuita (smtp2web), además de ser gratuita, el código de la misma aplicación está disponible como código libre. A continuación una breve guia de como utilizar este servicio.

El proceso es sencillo, solo necesitas una cuenta de Google para utilizar el servicio.

Tienes dos opciones, utilizar tu propio dominio o una sola cuenta con el dominio @smtp2web.com, para recibir e-mails con tu propio correo necesitas tener acceso a los ‘MX records’ de tu dominio. 

Para configurar tu dominio en smtp2web, haz click en ‘Add domain mapping’, donde te pedirán el nombre de tu dominio y la dirección en donde vas a recibir el post, el dominio de la dirección de POST debe coincidir con la dirección que utilizas para recibir dominios, por lo tanto debe ser algo como ‘http://post.tudominio.com/emailposting’.

Nota: Todo correo entrante a tudominio.com sera dirigido a smtp2web, si deseas seguir recibiendo correo normal con ese dominio, te recomiendo que utilices un subdominio algo como post.tudominio.com

Luego sigue los pasos para confirmar que el dominio que estas utilizando te pertenece, solo debes subir a tu servidor un archivo vacío con el nombre que smtp2web te va a proporcionar.

El siguiente paso es añadir lo siguiente a tus DNS records:

post.tudominio.com. MX 5 mx1.smtp2web.com.
post.tudominio.com. MX 5 mx2.smtp2web.com.

Si seguiste todos estos pasos correctamente, ya tu aplicación es capaz de recibir e-mails, cualquier e-mail enviado a usuario@post.tudominio.com será automáticamente enviado como un POST a la dirección http://post.tudominio.com/emailposting.

Aún no hemos terminado, tu aplicación necesita entender ese POST.

En PHP es sencillo, solo utiliza el siguiente código.

<?php
$from = htmlentities($_GET['from']);
$to = htmlentities($_GET['to']);
$body = $_POST['body']
/* tu código, insertar a la BD, etc. */
?>

En Ruby on Rails es un poco mas complicado, RoR por motivos de seguridad no permite hacer POST desde otro servidor/aplicación, así que debes añadir lo siguiente al inicio de tu ‘controller’ para pasar por alto esta medida de seguridad en un ‘action’, en este caso, ‘emailposting’.

protect_from_forgery :except => :emailposting

Para analizar esta data correctamente, te recomiendo que utilices una librería llamada TMail, con esta puedes sacar cualquier tipo de información del e-mail, incluyendo cualquier archivo adjunto que tenga.

$ gem install tmail

Luego debes crear un ‘action’ en tu ‘controller’

def emailposting
  mail = TMail::Mail.parse(request.raw_post.to_s)
  from = mail.from.to_s
  to = mail.to.to_s
  subject = mail.subject.to_s
  body = mail.body.to_s
  # tu código, insertar a la BD, etc.
end

El resto, es responsabilidad tuya, espero les haya gustado esta primera guía para Tequilog.

  • Share/Bookmark