Tag Archives: Ruby

Ruby: Convertir Números en Palabras (Cantidad con Letra)

Cierto día en el trabajo nos pusimos a hacer un pequeño gem que le hace un override a la clase Numeric de Ruby, agregando un método de instancia to_words que entrega el número en texto. El número puede estar entre 0 y 9 quintillones (como si realmente necesitaras esta cantidad 😀 ). Esta hecho para que lo escriba en español de la siguiente forma:
$ irb(main):001:0> require 'rubygems'
$ => true
$ irb(main):002:0> require 'number_to_words'
$ => true
$ irb(main):003:0> 5678.to_words
$ => "cinco mil seiscientos setenta y ocho"

Y para que te sirva para un cheque, osea para uso monetario….

$ irb(main) :004:0> number = 4567.90
$ => 4567.9
$ irb(main):005:0> number.to_words.capitalize << " pesos " << (number.to_s.split(".")[1] || 0).rjust(2,'0')<< "/100 M.N."
$ => "Cuatro mil quinientos sesenta y siete pesos 09/100 M.N."

Hasta el momento nos ha funcionado a la perfección.
Para instalarlo y usarlo hechenle un ojo al sitio de github http://github.com/innetra/number_to_words/tree/master.

Si le encuentran defectos, errores o se les ocurre una mejora dejenme saber para ver si se incluye. Espero les sirva. Saludos.
Recommend Me

Advertisements

Sending mail smtp gmail, with attachment using Ruby on Rails: ActionMailer

Ruby on rails has a native class to send email. It may look easy but it can get confusing when you have to configure your rails app to manage this.
All the configuration must be in the environment.rb file or in any specific environment file ( development.rb, production.rb, test.rb), however I sugest using environmet.rb so you won’t have to repeat configuration.

All the information on configuration is at http://api.rubyonrails.org but here is an example using gmail.

config/environment.rb
config.action_mailer.delivery_method = :smtp

# I do care if the mailer can't send
config.action_mailer.raise_delivery_errors = true

# Include your app's configuration here:
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => "587",
:domain => "my_app_domain", #Example: blog.local
:authentication => :plain,
:user_name => "my.gmail.account",
:password => "th1s1s4l33tpwd!"
}

That is all the configuration to send the mail, now you need to create your mailer.
$ script/generate mailer my_mailer

Write all the logic of this mailer on the “model” my_mailer.rb, here is an example that also sends an attachment, I asume that you have a user model or a person model, this model should have a field name and email:

app/models/my_mailer.rb
class MyMailer < ActionMailer::Base

def email(recipient)
recipients recipient.email
from "my.gmail.account@gmail.com"
subject "This is a test mail"
body :user => recipient # Im sending the recipient object as a local variable in a partial, but you will access it as an instance variable

@file_name = "#{RAILS_ROOT}/public/attachment.txt"
create_attachment
attachment :content_type => "text/plain",
:filename => "Some useless attachment",
:body => File.read(@file_name)
delete_attachment_file
end

protected
def create_attachment
attachment = File.new(@file_name, 'w')
attachment.puts "I am a useless text file"
attachment.puts " C(0_0)D "
attachment.close
end

def delete_attachment_file
File.delete(@file_name)
end
end

Now let’s make a view for the mail layout. This view will define the body or content of your mail.
So now you need to create a file named email.erb this is because our method that sends the mail is named email, so this basically works as the views for the controller actions. Create your file under views/my_mailer. Here is an example that uses the local variable user that I send from the email method.

app/views/my_mailer/email.erb

Hello . I have an attachment for you :)

Ok now you have almost everything done, but we still have to call our email method. This is done using a dynamic method deliver_my_method_name(param_1, param_2, …, param_n)

This is an example of this dynamic method called from the person model.

app/models/person.rb
class Person < ActiveRecord::Base
def send_email
MyMailer.deliver_email(self) # I am sending the person as a parameter.
end
end

One last thing, to send email using accounts that need tsl like gmail you need some libraries that will give you extra methods. What i did to solve this was to create a lib file in my Rails application under the lib directory ( I know this is obvious but i have to be specific 😀 ). This is the code of that file, I found this code googling and I just copied it into my app, it works for me and I hope it’ll work for you:

lib/smtp_tsl.rb
require "openssl"
require "net/smtp"

Net::SMTP.class_eval do
private
def do_start(helodomain, user, secret, authtype)
raise IOError, 'SMTP session already started' if @started
if RUBY_VERSION == "1.8.7"
check_auth_args user, secret if user or secret
else
check_auth_args user, secret, authtype if user or secret
end

sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
@socket = Net::InternetMessageIO.new(sock)
@socket.read_timeout = 60 #@read_timeout
#@socket.debug_output = STDERR #@debug_output

check_response(critical { recv_response() })
do_helo(helodomain)

if starttls
raise 'openssl library not installed' unless defined?(OpenSSL)
ssl = OpenSSL::SSL::SSLSocket.new(sock)
ssl.sync_close = true
ssl.connect
@socket = Net::InternetMessageIO.new(ssl)
@socket.read_timeout = 60 #@read_timeout
#@socket.debug_output = STDERR #@debug_output
do_helo(helodomain)
end

authenticate user, secret, authtype if user
@started = true
ensure
unless @started
# authentication failed, cancel connection.
@socket.close if not @started and @socket and not @socket.closed?
@socket = nil
end
end

def do_helo(helodomain)
begin
if @esmtp
ehlo helodomain
else
helo helodomain
end
rescue Net::ProtocolError
if @esmtp
@esmtp = false
@error_occured = false
retry
end
raise
end
end

def starttls
getok('STARTTLS') rescue return false
return true
end

def quit
begin
getok('QUIT')
rescue EOFError, OpenSSL::SSL::SSLError
end
end
end

Enjoy. Leave me a comment if you see anything funny, annoying, cool or just to say hello.
Recommend Me

Leer HTML de un sitio externo con Ruby on Rails y Hpricot

Hace un par de semanas mi profesor de Sistemas Distribuidos en el ITESO nos pidió hacer una especie de Web Service que te entregara información del mercado cambiaro en formato XML. Esto sonaba bastante sencillo, sin embargo todo se complicó cuando nos pidio información real tomada de la página de un banco, debiamos leerla en HTML.
La idea entonces era leer el código HTML de una página web confiable que presentara esta información y nosotros convertirla en XML con el formato solicitado. Al principio si le batalle en buscar mejor un Web Service ya hecho y gratuito que presentara esta información, sólo encontre uno aqui, sin embargo no pude encontrar un API ni nada parecido que me facilitara el uso.
Para este momento ya tenia el tiempo encima así que como de costumbre acudí a la comunidad de RoR para ver que herramientas tenía a la mano para leer HTML. Me encontré con Hpricot que es un gem que me solucionó la vida. La solución final quedo muy simple.

Primero hize un modelo CurrencyService que se conecta con el sitio web del que obtuve la información, lo lee como un string y este lo convierte a un Hpricot, después usando la librería Hpricot busca por ID los datos que se necesitan, el controlador simplemente presenta la información en formato XML y listo. Aqui dejo el código, solo que no revelaré la fuente de información ya que no se si es legal.

currency_service.rb
require ‘open-uri’
require ‘hpricot’

class CurrencyService < ActiveRecord::Base
def get_data(id)
html = Hpricot(open("http://www.urlfalso.fake").read)
return (html/id).inner_html
end

def get_xml_content
@currencies = {
{:CURRENCY_EQV => ""},
{:CUR_CODE => "USD", :MEX_EQV => get_data("#FIX_DATO").gsub(/ /,'').chomp},
{:CURRENCY_EQV => ""},
{:CUR_CODE => "EUR", :MEX_EQV => get_data("#EURO_DATO").gsub(/ /,'').chomp},
{:CURRENCY_EQV => ""},
{:CUR_CODE => "YEN", :MEX_EQV => get_data("#YEN_DATO").gsub(/ /,'').chomp},
{:CURRENCY_EQV => ""},
{:CUR_CODE => "CAN", :MEX_EQV => get_data("#LIBRA_DATO").gsub(/ /,'').chomp}
}.to_xml

end

end

curency_service_controller.rb
class CurrencyServiceController < ApplicationController

def index
@currency_service = CurrencyService.new
send_data( @currency_service.get_xml_content, :type => "text/xml",
:filename => "currencies.xml" )
end

end

Asi de simple es…