Saturday, August 31, 2013

Spree

Spree es una aplicación "open source e-commerce" que se puede integrar fácilmente en una aplicación Rails, para convertirla en una tienda que venda productos.



 Spree pone a disposición módulos que cubren la mayor parte de los requerimientos avanzados de una tienda online y en el caso de que el cliente solicite algo específico es flexible y adaptable. Spree está desarrollado de manera modular en lo que se conoce como "gems" o plugins, esto permite que los módulos que se desarrollen a mayores podrán ser usados en otros proyectos de manera sencilla y ágil.

Spree cuenta con una parte de backend muy potente que permite crear y editar productos, gestionar pedidos, configuración de usuarios, configurar métodos de envío (proporcionar diferentes tipos de calculadora de costes de envío), permite configuración con diferentes métodos de pago, permitiendo la integración con paypal, tpv, etc etc



Todas estas características hacen de este gestor una herramienta muy apetecible para llevar a cabo el desarrollo de tiendas online.

Friday, March 15, 2013

Action Mailer: Sendgrid


En una aplicación Rails podemos configurar diferentes cuentas SMTP para el envío de emails.
Dentro de config/environments podemos especificar digamos la cuenta que vamos a usar para el envío general de emails. En el environment correspondiente: development.rb, production.rb, especificaríamos dicha cuenta:

# Disable delivery errors, bad email addresses will be ignored
  # Don't care if the mailer can't send
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.smtp_settings = {
    :enable_starttls_auto => true,
    :address => "smtp.gmail.com",
    :port => 587,
    :domain => "",
    :authentication => "plain",
    :user_name => "", #should be you@domain.com
    :password => ""
  }


Si no se especifica lo contrario esta cuenta será la que se utilice para las diferentes clases que extiendan de  ActionMailer::Base.

Imaginemos que ahora tenemos la clase EnvioMasivoMailer que se usará para el envío masivo de emails a diferentes usuarios. Algo tal como esto:
class EnvioMasivoMailer < ActionMailer::Base
   def email_for_users(opts = {})
   end
end

En este caso podríamos considerar oportuno que por sus características deberíamos usar sendgrid. Sendgrid permite enviar hasta medio millón de emails por mes con la garantía de que no acabarán en la caja de spam.
Con estadísticas, informes de spam, filtros de cuentas inexistentes, opciones de importación y muchas más funciones, es uno de los grandes en el mundo del email marketing.
¿Como configuraríamos para la clase que hemos definido este servidor de correo?











En primer lugar nos podríamos definir un archivo mailer_sendgrid.yml dentro de la carpeta config con la configuración:
send_grid_conf:
  address:        "smtp.sendgrid.net"
  port:           587
  authentication: !ruby/sym plain
  user_name:      ""
  password:       "" 


Y ya dentro de nuestra clase haríamos lo siguiente, sobreescribir el smtp_settings del action mailer para usar sendgrid:
class EnvioMasivoMailer < ActionMailer::Base
   def email_for_users(opts = {})
      headers_email["X-SMTPAPI"] = {:to => opts[:array_of_recipients]}.to_json 
      mail(headers_email) do |format|
              format.html
      end


   end
   
   cattr_accessor :send_grid_config

   self.send_grid_config = YAML::load(File.open("#{Rails.root}/config/mailer_sendgrid.yml"))

   # Esta configuracion es para produccion, se sobreescribe el smtp_settings del environment correspondiente para meter la configuración de send_grid
  
   def self.smtp_settings
      send_grid_config['send_grid_conf'].symbolize_keys
   end


end
De esta manera sólo esta clase usaría sendgrid como método de envío de emails, el resto usaría la que especificamos dentro del environment correspondiente.

Thursday, March 07, 2013

Rails: Rakes


Sirven para crear y automatizar tareas. Algunas de las rakes más útiles que define rails pueden ser:

  • rake db:migrate: actualiza la base de datos. Con el parámetro VERSION=X, después del comando, la actualiza a la versión especificada.
  • rake stats:  nos da estadísticas de nuestra aplicación.
  • rake db:schema:load - Carga el fichero schema.rb en base de datos
  • rake db:fixtures:load - Carga los datos de las fixtures en el entorno de base de datos que especifiquemos. Puedes cargar fixtures especificas con FIXTURES=x,y
  • etc

 También nos podemos crear nuestras propias rakes. Para ello crearemos dentro de la estructura de carpeta lib/tasks un fichero terminado en .rake. La siguiente rake sirve para cargar datos de una o varias tablas en ficheros .yml:


namespace :db do
  desc 'Create YAML test fixtures from data in an existing database.
  Defaults to development database. Set RAILS_ENV to override.'

  task :load_data_table_to_yml => :environment do
    sql = "SELECT * FROM %s"
    skip_tables = ["schema_info", "sessions"]
    ActiveRecord::Base.establish_connection
    tables = ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : ActiveRecord::Base.connection.tables - skip_tables
    tables.each do |table_name|
      i = "000"
      if File.exists?("#{Rails.root}/test/fixtures/#{table_name}.yml")
      else
        File.new("#{Rails.root}/test/fixtures/#{table_name}.yml", "w+")
      end
      File.open("#{Rails.root}/test/fixtures/#{table_name}.yml", 'w') do |file|
        data = ActiveRecord::Base.connection.select_all(sql % table_name)
        file.write data.inject({}) { |hash, record|
          hash["#{table_name}_#{i.succ!}"] = record
          hash
        }.to_yaml
      end
    end
  end
end 
La forma de ejecutar esta rake sería:

rake db:load_data_table_to_yml

Donde si os fijais el 'db' es el namespace que definimos dentro de la rake y sirve para agrupar digamos tareas que son similares.Y 'load_data_table_to_yml' es el task que hemos definido en la rake. No tiene nada que ver con el nombre que le hemos dado al fichero .rake. Para pasarle parámetros se pasan a continuación de la instrucción en mayúsculas y dentro de la rake se recogen dentro de la variable de entorno ENV como se puede ver en el ejemplo.

Thursday, February 21, 2013

SCRUM: Metodología ágil


Hoy en día en cualquier proyecto resulta fundamental poder introducir cambios con rapidez y en cualquier fase del mismo. ¿Por qué? Pues ya sea por especificaciones del cliente o bien porque en mitad de un desarrollo nos dimos cuenta de que vamos por el camino equivocado.

Con esta idea de gestionar los proyectos de una manera ágil nació el concepto de SCRUM. En los años 80 los japoneses Takeuchi y Nonaka estudiaron las prácticas de empresas con buenos resultados de rapidez y flexibilidad en la producción: cámaras de fotos de Canon, fotocopiadoras de Xerox, automóviles de Honda, ordenadores de HP y otros.

Estas son algunas de las claves de SCRUM:

  1. Equipos pequeños y auto-organizados. Un equipo pequeño en el que los propios miembros se auto-organizan y entre los que existe una comunicación transparente hace que se sientan más cómodos, motivados y valorados.
  2. Historias de usuario. Teniendo en cuenta el punto de vista del usuario y del cliente se recogen los requisitos del producto que van a formar lo que se llama 'product backlog'. A cada una de las tareas que conforman esa lista se les asigna una prioridad
  3. Sprints. Conforma un período de tiempo corto que viene siendo de 2 a 4 semanas. Se trata de ver que tareas del backlog se van a llevar a cabo ('sprint backlog') con el objetivo de tener al final del sprint algo entregable y que funcione.
  4. Reuniones diarias. Se trata de que el equipo haga reuniones diarias que no van más alla de 10-15 minutos y en el que los miembros del equipo permanecen de pie para prestar la máxima atención posible. Se trata de que cada miembro del equipo responda de forma breve a 3 preguntas clave:
    • ¿Qué has hecho desde ayer?
    • ¿Qué tienes planeado hacer mañana? 
    • ¿Has encontrado algún problema para conseguir tu objetivo? 

Tuesday, February 19, 2013

Rails: Sass


Sass (Syntactically Awesome Stylesheets), es un meta-lenguaje que proporciona una sintaxis más simple y elegante para escribir CSS e implementa varias características útiles para la creación de hojas de estilo manejables.

Características


  1. Anidación. (seguir la filosofía DRY)
     .container{
          width: 200px;
     }
     .container .sms{
               border: 1px solid red;
     }
     .container .sms .title{
               color: red;
     }
     .container .section{
              margin-left:5px;
     }
     .container .section .title{
              color: #0000000;
    }
    
    .container{
        width: 200px;
        .sms {
              border: 1px solid red;
              .title { color: red;}
        }
       .section{
              margin-left:5px;
              .title{ color: #0000000;}
      }
  2. Variables. Las variables se declaran con el símbolo "$" y son muy útiles para declarar valores comunes en archivos CSS que son usadas en muchas partes del código. Podemos utilizar variables para representar los colores, tamaños, porcentajes...
    .content-navigation {
      border-color: #3bbfce;
      color: #2b9eab;
    }
    
    .border {
      padding: 8px;
      margin: 8px;
      border-color: #3bbfce;
    }
    
    $blue: #3bbfce;
    $margin: 8px;
    
    .content-navigation {
      border-color: $blue;
      color:
        darken($blue, 9%);
    }
    
    .border {
      padding: $margin;
      margin: $margin;
      border-color: $blue;
    }
    
    
  3.  Mixins. Un mixin es un fragmento de Sass que puede aplicarse fácilmente a otro selector, digamos que son como funciones. Para definir un mixin, todo lo que necesitas para escribir es @mixin, seguido por el nombre de la mixin y su estilo. uando se desea utilizar el mixin, sólo es llamarlo con la etiqueta @include.
    border-radius: 5px;  
    -moz-border-radius: 5px;  
    -webkit-border-radius: 5px;  
    
        @mixin rounded-corners {  
          border-radius: 5px;  
          -moz-border-radius: 5px;  
          -webkit-border-radius: 5px;  
        }  
         .content {  
          color: #FFF;  
          padding: 5px 12px;  
          margin: 10px 0;  
          font-size: 16px;  
          @include rounded-corners;  
        }  
    
  4. Herencia. Sass puede decir a un selector que herede todos los estilos de otro sin duplicar las propiedades CSS.
  5.  
    .error, .formError {
      border: 1px #f00;
      background: #fdd;
    }
    
    .formError {
      border-width: 3px;
    }
    
     
    .error {
      border: 1px #f00;
      background: #fdd;
    }
    
    .formError {
      @extend .error;
      border-width: 3px;
    }
    



    Friday, February 15, 2013

    Rails: Sitemap generator


    SitemapGenerator genera sitemaps para tu aplicación Rails.


    Instalación

    1. Añadir la línea gem 'sitemap_generator' al archivo Gemfile
    2. Ejecutar el comando rake sitemap:install
    Esto generará el archivo config/sitemap.rb que contiene la lógica para generar los ficheros sitemap.xml.


    Desarrollo

    SitemapGenerator::Sitemap.add_links do |sitemap|
    Article.find_each do |article|
      sitemap.add article_path(article), :lastmod => article.updated_at
    end
    end
    
    
    
    
    En este ejemplo se añadirán al sitemap las rutas referentes a artículos.

    Las opciones que se pueden añadir para cada url son las siguientes:

    1. priority La prioridad de una url respecto a otras de la web. Valores válidos: de 0.0 a 1.0. Default 0.5 
    2. changefreq Uno de: always, hourly, daily, weekly, monthly, yearly, never. Default weekly
    3. lastmod Fecha de última modificación. Default Time.now
    4. host Optional host for the link's URL. Defaults to default_host
    Una vez hecho esto si ejecutamos el comando rake -s sitemap:refresh los sitemaps serán generados en la carpeta public con la siguiente estructura de ficheros: sitemap_index.xml.gz, sitemap1.xml.gz, sitemap2.xml.gz, etc.

    Si queremos cambiar la carpeta donde guardar los sitemaps entonces bastará con añadir en el sitemap.rb la siguiente instrucción:

    
    
    
    
    SitemapGenerator::Sitemap.sitemaps_path = 'sitemaps/'
    
    


    Monday, February 11, 2013

    Rails: Observers


    En este patrón un objeto (el publicador o la fuente) informa a un conjunto de objetos interesados (los suscriptores) cuando su estado cambia.

    La clase ActiveRecord::Observer sigue un patrón Singleton. Este patrón garantiza que como máximo habrá una instancia de una clase.

    Los observadores de forma predeterminada se asignan a la clase con la que comparten un nombre. Así AuditoriaObserver estará ligado a la observación de auditoria. Si deseas asignar un nombre diferente a la clase a la que estás interesado en observar, puede utilizar el método de la clase Observer.observe ya sea a través de la clase concreta (Tweet) o un símbolo de esa clase (:tweet).

    Veámos un ejemplo para ver el comportamiento de este patrón:


    class AuditoriaObserver < ActiveRecord::Observer
    
      observe :tweet
      def after_create(auditoria)
        contact.logger.info('Nuevo tweet publicado!')
      end
    
      def after_destroy(auditoria)
        contact.logger.warn("Tweet con id: #{auditoria.id} fue borrado!")
      end
    end
    

    Como se puede ver en el ejemplo tenemos una clase Observer que observa a la clase Tweet, de tal manera que cuando se cree un objeto de este tipo o se borre tendremos constancia de ello.

    Estos métodos son callbacks que podrían ir perfectamente en la clase Tweet, pero el hacer uso de este tipo de patrones...nos permite extraer de los modelos todo ese código que no tiene que ver directamente con el modelo.

    Friday, February 01, 2013

    Rails: Eager Loading


    Una forma de mejorar el rendimiento en una aplicación es reducir el número de consultas SQL. Puedes hacer esto mediante una "precarga" o eager loading.

    Imaginemos que tenemos el siguiente modelo:
    
    
    
    class User < ActiveRecord::Base
      
       has_many :articles 
     
    end
    
    
    class Article < ActiveRecord::Base
      
       belongs_to :user
     
    end
    

    Si quisieramos pintar todos los articulos publicados en un periódico con la información del usuario que lo escribió, tendríamos algo similar a esto:
    @articles = Article.find(:all)
    
    @articles.each do |a|
      %p = a.title
      %p = a.user.name
    end
    
    El problema de esto es que si tenemos n articles estaríamos haciendo n accesos a base de datos para recuperar el user que lo escribió.
     

    Para evitar esto se puede usar precisamente el eager loading, es decir hacer una precarga de esos users, para luego no tener que acceder a base de datos. La solución sería la siguiente:

    @articles = Article.find(:all, :include => :users)
    

     Esto haría que además de acceder a la tabla articles hiciese una query de la forma:

    User Load (0.1ms)  SELECT `users`.* FROM `users` WHERE (`users`.article_id IN (1,2,3,4,5,6,7,8,9,10,50,102,103,28,101,16,25,22,78,80,84,86,88,89,99,105,107))


    Rails SQL Caching


    La forma en que funciona Rails SQL Caching es que las consultas se almacenan en caché durante la ejecución de una acción. Es importante observar que las memorias caché de consulta se crean en el inicio de una acción y son destruidas al final de esa acción y por lo tanto persiste sólo durante la ejecución de la acción.

    Puede ser que no deseemos este comportamiento, imaginemos que queremos sacar un usuario de manera aleatoria. Con el sql caching siempre obtendríamos los mismos resultados...


    User.find(:first, :order => "rand()") 



    Si queremos evitar que durante la acción el resultado siempre sea el mismo debemos hacer lo siguiente:



    class User < ActiveRecord::Base
      def self.usuario_aleatorio
        uncached do
          find(:first, :order => "rand()")
        end
      end
    end
    
    
    
    
    
    

    Thursday, January 24, 2013

    Rails: Configuración del entorno específico


    En este post quiero comentar un plugin interesante para la configuración de un entorno específico en un proyecto Rails.

    Se añade al GemFile la siguiente línea: gem "rails_config". RailsConfig ayuda a administrar la configuración del entorno específico. Lo único que tenemos que hacer es bundle install. Una vez que hagamos esto ejecutamos la siguiente instrucción: rails g rails_config:install

     En nuestra aplicación vamos a tener las siguientes carpetas:
    config/settings.yml
    config/settings/development.yml
    config/settings/production.yml
    config/settings/test.yml


    Es decir vamos a tener un archivo YAML por cada uno de los entornos de nuestra aplicación y un archivo común para todos los entornos que es el settings.yml; es decir será visible por todos los entornos. Dependiendo del entorno en el que tengamos levantada la aplicación leerá de un fichero u otro.

    La instrucción que ejecutamos antes creará un archivo en config/initializers, rails_config.rb, donde se define el nombre de la constante a través de la cual vamos a acceder a los parámetros definidos para cada entorno. Por defecto se llama Settings. Esta constante se puede cambiar por la que consideremos oportuna.



    Ejemplo

    Imaginemos que tenemos definido lo siguiente en cualquiera de los archivos mencionados:

    size: 2
    section:
      size: <%= 1 + 2 + 3 %>
      servers: [ {name: yahoo.com}, {name: amazon.com} ]
     
    Para poder acceder a estas variables desde cualquier parte de nuestra aplicación haríamos lo siguiente:

    Settings.size   # => 2
    Settings.server # => google.com
    Settings.section.size # => 6
    Settings.section.servers[0].name # => yahoo.com
    Settings.section.servers[1].name # => amazon.com
    

    Monday, January 21, 2013

    proc y lambda en Ruby


    En este post vamos a hablar de como su usan los procs y lambdas en Ruby así como las diferencias que existen entre ambos.


    La primera diferencia que existe entre ambos es en el paso de parámetros.

             ruby-1.9.3-p125 :003 > p = proc{|x, y| puts x+y}
             => #<Proc:0x000000067de2a8@(irb):3>

             ruby-1.9.3-p125 :004 > p.call 1,2
             3
             => nil

             ruby-1.9.3-p125 :006 > p.call 1,4,"prueba"
             5
             => nil

            ruby-1.9.3-p125 :007 > l = lambda{|x, y| puts x+y}
            => #<Proc:0x000000068f1d20@(irb):7 (lambda)>

            ruby-1.9.3-p125 :010 > l.call 1,2
            3
            => nil

            ruby-1.9.3-p125 :011 > l.call 1,2, "prueba"
            ArgumentError: wrong number of arguments (3 for 2)
            ...

    Como podemos ver proc ignora los demás parámetros que le pasamos a mayores, sin embargo lambda da un error.


     Comportamiento con el método return:                                                                                                
            ruby-1.9.3-p125 :018 > l = lambda do
            ruby-1.9.3-p125 :019 >     1 +2
            ruby-1.9.3-p125 :020?>   return "funciona"
            ruby-1.9.3-p125 :021?>   3 + 4
            ruby-1.9.3-p125 :022?>   end
            => #<Proc:0x00000006940498@(irb):18 (lambda)>
            ruby-1.9.3-p125 :023 > l.call
            => "funciona"
     
            ruby-1.9.3-p125 :024 > p = proc do
            ruby-1.9.3-p125 :025 >     1 +2
            ruby-1.9.3-p125 :026?>   return "funciona"
            ruby-1.9.3-p125 :027?>   3 + 4
            ruby-1.9.3-p125 :028?>   end
            => #<Proc:0x00000005976030@(irb):24>
            ruby-1.9.3-p125 :029 > p.call
            LocalJumpError: unexpected return


            ruby-1.9.3-p125 :030 > def ejemplo_proc
            ruby-1.9.3-p125 :031?>   p = Proc.new { return "asi me permite hacer return"}
            ruby-1.9.3-p125 :032?>   p "tambien lo veo"
            ruby-1.9.3-p125 :033?>   p.call
            ruby-1.9.3-p125 :034?>   p "esto ya no lo puedo ver"
            ruby-1.9.3-p125 :035?>   end
            => nil
            ruby-1.9.3-p125 :036 > ejemplo_proc
           "tambien lo veo"
            => "asi me permite hacer return"

            ruby-1.9.3-p125 :037 > def ejemplo_lambda
            ruby-1.9.3-p125 :038?>   p = lambda { return "asi me permite hacer return"}
            ruby-1.9.3-p125 :039?>   p "tambien lo veo"
            ruby-1.9.3-p125 :040?>   p.call
            ruby-1.9.3-p125 :041?>   p "esto ya no lo puedo ver"
            ruby-1.9.3-p125 :042?>   end
            => nil
           ruby-1.9.3-p125 :043 > ejemplo_lambda
           "tambien lo veo"
           "esto ya no lo puedo ver"
           => "esto ya no lo puedo ver"

    Saturday, January 19, 2013

    DRY: Metaprogramación


    Ruby es un lenguaje dinámico y precisamente la metaprogramación digamos que no es más que escribir programas que escriben programas. De ahí el nace el concepto de DRY ó "no te repitas a ti mismo". Veamos esto con un ejemplo sencillo:

    Imaginemos que tenemos un Tweet que puede tener 3 estados: pendiente, publicado y censurado.
    En un primer momento se nos puede ocurrir definir 3 constantes para la clase Tweet que identifiquen cada uno de los estados anteriores:

    class Tweet < ActiveRecord::Base

       PENDING = 0

       PUBLISHED = 1

       CENSURED = 2

    end 


    Ahora se nos podría ocurrir ir definiendo todos aquellos métodos de clase que necesitaríamos para extraer de base de datos todos los tweets en estado de pendientes, publicados o censurados. O incluso métodos de instancia para saber el estado de un tweet en concreto. Algo de esta manera:

    class Tweet < ActiveRecord::Base

       PENDING = 0

       PUBLISHED = 1

       CENSURED = 2

       def self.all_pending
         find(:all, :conditions => { :status => PENDING }
       end

      def self.all_published
        find(:all, :conditions => { :status => PUBLISHED }
      end

      def self.all_censured
        find(:all, :conditions => { :status => CENSURED }
      end

      def pending?
        self.status == PENDING  
      end

      def published?
        self.status == PUBLISHED  
      end

      def censured?
        self.status == CENSURED  
      end

    end

    Sin embargo se puede hacer mejor, más DRY, y con menos posibilidad de errores usando métodos dinámicos. Veamos el código para entenderlo de manera rápida y sencilla:

    class Tweet < ActiveRecord::Base 
        STATUSES = { 
            :pending => 0, 
            :published => 1, 
            :censured => 2 
        } 
        STATUSES.each do |status, value| 
            define_method :"#{status}?" do 
                self.status == value 
            end 
            define_method :"#{status}!" do 
                self.status = value 
            end 
        end 
        class <<self
          STATUSES.each do |status_name|
             define_method "all_#{status_name}" do
               find(:all, :conditions => { :status => status_name }
             end
          end
        end
    end

    Como se puede ver no repetimos tanto código que es lo que nos hace ser más DRY. Definimos el conjunto de estados como una Hash para poder recorrer ese conjunto y usamos define_method que nos da más flexibilidad que def ya que nos permite pasarle un parámetro, en este caso el estado, e ir definiendo de manera dinámica los distintos métodos que comentábamos anteriormente.

    Wednesday, January 16, 2013

    Behavior-Driven Development (BDD): Cucumber

    Desarrollo guiado por comportamiento, o Behavior Driven Development (BDD) es una técnica de Desarrollo Agil de Software que fomenta la colaboración entre desarrolladores, testers, analistas y personas del negocio en un proyecto de software. Crea un entendimiento común de todos los involucrados y ayuda a eliminar malos entendidos sobre lo que el sistema debe hacer.

    Frameworks de BDD

     Las herramientas de BDD se centran en describir el comportamiento de un software de una manera muy comprensible para todos los involucrados. En este post vamos a describir la herramienta Cucumber

    Cucumber

    Cucumber es una herramienta que permite ejecutar tests a partir de una descripción funcional en texto plano.
    El poder de Cucumber radica en la facilidad de describir un comportamiento determinado. Esta descripción se realiza en Gherkin, un Business Readable DSL que permite que cualquier persona defina reglas sin necesidad de contar con conocimientos de programación.

    Estos tests brindan la posibilidad de ser verificados por analistas y personas no técnicas que quizás sean expertos en el dominio de la aplicación.

    Features

    Una feature es algo que el software hace o debería hacer. La estructura general de una feature es la siguiente:

    Feature: <short description>
    <story>
    <scenario 1>
    ...
    <scenario n>

    El formato común para el <story> es:

    As a <role>
    I want <feature>
    so that <business value>

    que responde a tres cuestiones importantes: 
    1. ¿Quién está usando el sistema?
    2. ¿Qué están haciendo?
    3. ¿Por qué les importa?

    Scenarios

    Una feature es definida por uno o más escenarios. Un escenario es una secuencia de pasos.
    Un escenario se compone de tres secciones relacionadas con los 3 tipos de medidas:

    1. Given: Esto crea condiciones previas, o el contexto para el escenario.
    2. When: Comportamiento que se está enfocando.
    3. Then: Postcondiciones ... comprueba que se hace lo correcto en el comportamiento que se está enfocando en el paso 2.

    La forma general de un escenario es la siguiente:

    Scenario: <description>
    <step 1>

    <step n>


    Proceso de instalación y ejemplo de ejecución

            En el GEMFILE añadir:

    group :test do

        gem 'cucumber-rails'
        gem 'capybara'
        gem 'database_cleaner'

    end

    • Ejecutar bundle install en una consola.
    • Ejecutar rails generate cucumber:install (genera las carpetas necesarias, entre ellas la de features)

    La estructura que toma dentro del proyecto es la siguiente:

    features:

    step_definitions

        web_steps.rb

    support

        env.rb (configuration file cucumber)

        paths.rb (Maps a name to a path)

            rails generate cucumber:feature “nombre de la feature” (rails generate cucumber:feature “Article”)

    Creara los archivos: manage_articles.feature donde se definen los posibles escenarios y article_steps.rb donde se definen los pasos intermedios:

    features:
    → step_definitions

        web_steps.rb

        article_steps.rb

    → support

        env.rb (configuration file cucumber)

        paths.rb (Maps a name to a path)

    → manage_articles.feature

    Ejemplo

    Definimos en manage_articles.feature un escenario de la forma:

    Feature: Manage articles

    In order to make a blog

    As an author

    wants to create and manage articles

    Scenario: Articles List

    Given I have articles titled Pizza, Breadsticks

    When I go to the list of articles

    Then I should see "Pizza"

    And I should see "Breadsticks"

    Se procede a definir los “steps” relevantes (cada step se va a corresponder con cada una de las líneas identificadas para el escenario definido), que atienden a expresiones regulares :

    En article_steps.rb:

    Given /^I have articles titled (.+)$/ do |titles|

    titles.split(', ').each do |title|

    Article.create!(:title => title)

    end

    end

    En web_steps.rb está definido el step para la segunda línea del escenario

    “When I go to the list of articles”:

    When /^(?:|I )go to (.+)$/ do |page_name|

    visit path_to(page_name)

    end




            cucumber features

    Using the default profile...

    ....

    1 scenario (1 passed)

    4 steps (4 passed)

    0m0.529s

    Tuesday, January 15, 2013

    Resque Hooks y Scheduler


    Existen diferentes tecnologías que se pueden utilizar para programar jobs en segundo plano: entre ellas utilizando un almacén de datos NoSQL como Redis y Resque para su gestión.

    En este artículo me gustaría hablar sobre los hooks y sobre resque-scheduler. Los hooks sirven para añadir comportamiento adicional a un plugin, en este caso al tratamiento y ejecución de un job y el segundo 'resque-scheduler' es una extensión para Resque que añade soporte para tratar jobs en un futuro. Veámos ambos conceptos con un poco más de tranquilidad y con ejemplos sencillos. Yo creo que ambos conceptos van un poco de la mano:

    Job Hooks

    Estos son algunos de los hooks que hay disponibles:


    • before_enqueue
    • after_enqueue
    • before_perform
    • after_perform
    • on_failure_retry  
    • etc

    Veamos por ejemplo el funcionamiento del hook on_failure_retry, un hook interesante ya que va añadir un compartimiento  adicional en el caso de que el job que ejecutemos falle.

    Imaginemos que tenemos un job que lo que hace es enviar emails en segundo plano a los usuarios de una aplicación:




    require 'resque'
    class EnvioEmailsJob < Jobs::Base
       def self.perform(opts = {})
          mail = UsuariosMailer.email_users(opts) # => a Mail::Message object
          mail.deliver   # sends the email
       end
    end


    Ahora vamos a añadir un hook y darle el comportamiento deseado en el caso de que el job que procesa el email fallara. Este es un punto interesante porque en determinadas aplicaciones podría ser un punto crítico y necesario para el correcto funcionamiento de la misma.
    A continuación defino como sería el código para añadir el hook y su funcionalidad, en este caso vamos a modificar su comportamiento a través del plugin resque-scheduler, que entre otras cosas tiene una función que nos permite reencolar el job que ha fallado y decirle cuando queremos que se ejecute, porque de otro modo se ejecutaría de manera recursiva y no queremos que suceda eso:


    module Jobs
      # Callbacks in jobs execution.
      # Esta clase debe ser la superclase de cualquier trabajo para controlar su      ejecución.
      
      class Base
          def self.on_failure_retry(e, *args)     
             next_execution = time_now.change(:min => 50)
             # función de resque-scheduler para reencolar el job y se ejecute en un    momento determinado, en este caso cada 50 minutos.
             Resque.enqueue_at(next_execution, self, *args)
          end 
      end
    end

    Scheduled Jobs

    Son tareas programadas, como vimos en el ejemplo anterior la sintaxis es de la forma:

    Resque.enqueue_in(5.days, SendFollowupEmail) # ejecutar un job en 5 días
    # ó
    Resque.enqueue_at(5.days.from_now, SomeJob) #  ejecutar un job a una hora especifica.

     




    Sunday, January 13, 2013

    Apache Thrift


    Es un framework JAVA para el desarrollo de servicios escalables multi lenguaje. Esto permite crear servicios que trabajan eficiente y transparentemente entre los lenguajes de programación más populares (C++, Java, C#,Python, Ruby, PHP entre muchos otros).
    Apache Thrift permite a los desarrolladores definir los tipos de datos e interfaces de servicios en un archivo único en lenguaje neutral y generar todo el código necesario para construir clientes RPC y servidores.

     Primeros pasos con Apache Thrift

    1. Descarga Apache Thrift
    2. Instalación
    3. Ahora ya puedes empezar a escribir tu primer archivo thrift. Para generar el código en el lenguaje que más os convenga o interese sólo teneis que ejecutar la siguiente instrucción:
    thrift --gen <lenguaje de programación> <nombre del fichero Thrift>

    
    


     Ejemplo de Apache Thrift con Ruby

    Vamos a definir una estructura sencilla de un objeto User con tipos de datos básicos, donde el sexo del usuario va ser un tipo de dato enumerado:

    enum SexType {
      MALE = 1,
      FEMALE = 2
    }

    struct User {
      1: string firstname,
      2: string lastname,
      3: i32 user_id = 0,
      4: SexType sex,
      5: bool active = false,
      6: optional string description
    }
    
    
    Guardamos el archivo como user.thrift por ejemplo.
    Si queremos generar el código ruby asociado al archivo .thrift que acabamos de especificar ejecutaríamos la siguiente instrucción:
    thrift --gen rb user.thrift