ActionSMS

De Open movilforum wiki

ActionSMS es un plugin para Rails que añade a ActionMailer (el mecanismo estándar de Rails para enviar e-mail) la capacidad de enviar SMS's, en principio a través de la API de Movistar (aunque crear una libreria para utilizar otra pasarela de envío es muy sencillo).

[editar] Inicio rápido

El plugin es bastante simple de usar:

1. Instálalo:

 $ script/plugin install http://action-sms.googlecode.com/svn/tags/action_sms

2. Crea el archivo config/sms.yml con el siguiente contenido:

 gateway: movistar
 login: <tú-número-de-móvil>
 password: <tu-password-para-la-API>

3. ¡Ya está! Ahora, cuando envíes mensajes con ActionMailer, Rails parseará la lista de destinatarios, y lo enviará como SMS a aquellos destinatarios que consistan en un número, y como e-mail a los demás, de forma completamente transparente. La forma de generar los mensajes, configurar el sistema, escribir los tests, etc., es la estándar de Rails (puedes leer una buena descripción de todos estos aspectos en el capítulo 24 del "Agile Web Development with Rails" o en el wiki de Rails.

[editar] Enviar SMS's desde Ruby (sin Rails)

ActionSMS se divide en dos partes: la parte puramente Rails de redefinición de ActionMailer, y la clase MovistarGateway que es la que maneja el envío de los SMS. Esto es con un doble objetivo: por un lado, poder incluir en el futuro otros gateways en el plugin (el gateway activo se configura en config/sms.yml y de momento sólo acepta el valor 'movistar'), y, por otro, poder usar esa clase en scripts "pure Ruby", lo cual sería tan simple como el siguiente ejemplo:

 require 'movistar_gateway'
 gateway = MovistarGateway.new('<login>', '<password>')
 gateway.send(['66666666', '777777777'], 'Texto del mensaje')

[editar] El ejemplo completo

Vamos a crear una agenda de contactos en la que cada vez que añadimos un contacto, le avise con un email y un SMS. Haremos uso intensivo de los generadores de Rails.

Lo primero, creamos el esqueleto de la aplicación:

 $ rails agenda -d sqlite3
 
     create  
     create  app/controllers
     create  app/helpers
     create  app/models
     create  app/views/layouts
     create  config/environments
     create  config/initializers
     create  db
     create  doc
     create  lib
     create  lib/tasks
     create  log
     create  public/images
     create  public/javascripts
     create  public/stylesheets
     create  script/performance
     create  script/process
     create  test/fixtures
     create  test/functional
     create  test/integration
     create  test/mocks/development
     create  test/mocks/test
     create  test/unit
     create  vendor
     create  vendor/plugins
     create  tmp/sessions
     create  tmp/sockets
     create  tmp/cache
     create  tmp/pids
     create  Rakefile
     create  README
     create  app/controllers/application.rb
     create  app/helpers/application_helper.rb
     create  test/test_helper.rb
     create  config/database.yml
     create  config/routes.rb
     create  public/.htaccess
     create  config/initializers/inflections.rb
     create  config/initializers/mime_types.rb
     create  config/boot.rb
     create  config/environment.rb
     create  config/environments/production.rb
     create  config/environments/development.rb
     create  config/environments/test.rb
     create  script/about
     create  script/console
     create  script/destroy
     create  script/generate
     create  script/performance/benchmarker
     create  script/performance/profiler
     create  script/process/reaper
     create  script/process/spawner
     create  script/process/inspector
     create  script/runner
     create  script/server
     create  script/plugin
     create  public/dispatch.rb
     create  public/dispatch.cgi
     create  public/dispatch.fcgi
     create  public/404.html
     create  public/500.html
     create  public/index.html
     create  public/favicon.ico
     create  public/robots.txt
     create  public/images/rails.png
     create  public/javascripts/prototype.js
     create  public/javascripts/effects.js
     create  public/javascripts/dragdrop.js
     create  public/javascripts/controls.js
     create  public/javascripts/application.js
     create  doc/README_FOR_APP
     create  log/server.log
     create  log/production.log
     create  log/development.log
     create  log/test.log

La opción -d sqlite3 es para usar una base de datos SQLite, opción siempre cómoda para el entorno de desarrollo, pero puedes usar la que quieras.

El siguiente paso es entrar al directorio de la aplicación y generar el scaffold para los contactos:

 $ script/generate scaffold Contact name:string email:string mobile:string
 
     create  app/models/
     exists  app/controllers/
     exists  app/helpers/
     create  app/views/contacts
     create  test/functional/
     create  test/unit/
     create  app/views/contacts/index.html.erb
     create  app/views/contacts/show.html.erb
     create  app/views/contacts/new.html.erb
     create  app/views/contacts/edit.html.erb
     create  app/views/layouts/contacts.html.erb
     create  public/stylesheets/scaffold.css
 dependency  model
     exists    app/models/
     exists    test/unit/
     create    test/fixtures/
     create    app/models/contact.rb
     create    test/unit/contact_test.rb
     create    test/fixtures/contacts.yml
     exists    db/migrate
     create    db/migrate/001_create_contacts.rb
     create  app/controllers/contacts_controller.rb
     create  test/functional/contacts_controller_test.rb
     create  app/helpers/contacts_helper.rb
      route  map.resources :contacts

Para crear la tabla correspondiente en la base de datos hay que ejecutar las migraciones:

 $ rake db:migrate
 
 == 1 CreateContacts: migrating ================================================
 -- create_table(:contacts)
    -> 0.0057s
 == 1 CreateContacts: migrated (0.0061s) =======================================

Ya podemos arrancar el servidor:

 $ script/server

Y probar nuestra flamante aplicación introduciendo esta URL en el navegador: http://0.0.0.0:3000/contacts

Puedes probar a añadir, borrar y modificar algunos contactos.

Ahora vamos a añadir la capacidad de avisar a los nuevos contactos por email. Lo primero será generar el mailer:

 $ script/generate mailer Notifier add
 
     exists  app/models/
     create  app/views/notifier
     exists  test/unit/
     create  test/fixtures/notifier
     create  app/models/notifier.rb
     create  test/unit/notifier_test.rb
     create  app/views/notifier/add.erb
     create  test/fixtures/notifier/add

Si abrimos app/models/notifier.rb veremos que ya se ha creado el método add, que es el que usaremos para enviar el email:

 class Notifier < ActionMailer::Base
 
   def add(sent_at = Time.now)
     @subject    = 'Notifier#add'
     @body       = {}
     @recipients = 
     @from       = 
     @sent_on    = sent_at
     @headers    = {}
   end
 end

Lo modificaremos ligeramente para que nos acepte como parámetro el contacto añadido, tenga un asunto más descriptivo, y alguna cosa más, para que quede así:

 class Notifier < ActionMailer::Base
 
   def add(contact)
     @subject    = 'Te han añadido como contacto'
     @body       = {:contact => contact}
     @recipients = contact.email
     @from       = 'miaplicacion@example.com'
     @sent_on    = Time.now
     @headers    = {}
   end
 end

Y por último editaremos la vista, que está en app/views/notifier/add.erb, con algo como esto:

 Hola, <%= @contact.name %>: ¡Te han añadido como contacto!

Lo único que nos falta es hacer que al crear un contacto se envíe el correo, lo cual haremos mediante un callback en el modelo Contact (app/models/contact.rb). Antento que aquí está el meollo de la cuestión:

 class Contact < ActiveRecord::Base
 
   after_create :send_message
 
   def send_message
     Notifier.deliver_add(self)
   end
 end

Al definir send_message como callback after_create, este método se ejecutará cada vez que se cree un contacto. El método, usando el mailer Notifier, enviará el mail add (que creamos hace un momento), pasándole como parámetro el propio usuario creado. No estaría de más, antes de hacerlo, comprobar que se ha introducido realmente un email válido, por ejemplo mediante validaciones, pero te dejaremos eso como ejercicio =;-)

Añádete a tí mismo como contacto y verás como te llega el email. Si tienes algún problema con la configuración del correo puedes consultar, como dijimos antes, el capítulo 24 del "Agile Web Development with Rails" o en el wiki de Rails.

Ahora vamos a hacer que la aplicación también notifique por SMS. Lo primero será instalar el plugin:

 $ script/plugin install http://action-sms.googlecode.com/svn/tags/action_sms
 
 + ./action_sms/MIT-LICENSE
 + ./action_sms/README
 + ./action_sms/Rakefile
 + ./action_sms/init.rb
 + ./action_sms/install.rb
 + ./action_sms/lib/action_sms.rb
 + ./action_sms/lib/movistar_gateway.rb
 + ./action_sms/tasks/action_sms_tasks.rake
 + ./action_sms/test/action_sms_test.rb
 + ./action_sms/uninstall.rb

Y configurarlo, creando el archivo config/sms.yml con el siguiente contenido:

 gateway: movistar
 login: <tu-numero>
 password: <tu-password>

Y ya, simplemente con hacer que el mailer añada como destinatario el número de móvil, se enviará el mensaje por las dos vías. Como recordarás, haremos eso editando app/models/notifier.rb y modificando la linea de los recipients:

 class Notifier < ActionMailer::Base
 
   def add(contact)
     @subject    = 'Te han añadido como contacto'
     @body       = {:contact => contact}
     @recipients = [ contact.email, contact.mobile ]
     @from       = 'miaplicacion@example.com'
     @sent_on    = Time.now
     @headers    = {}
   end
 end

Prueba, prueba ;-)