Monthly Archives: January 2009

auto_complete en Ruby on Rails

Esto solía ser nativo de rails en las primeras versiones, sin embargo, a partir de la 2.0 si mal no recuerdo, fue extraido a un plugin. Este plugin esta muy bueno para auto completar text_fields en formularios.
Para usarlo primero hay que instalarlo, asi que desde la carpeta vendor/plugins de nuestra aplicación rails:
$ git clone git://github.com/rails/auto_complete.git
$ rm -rf auto_complete/.git
O bien desde la carpeta root de tu proyecto Rails.
$ ./srcipt/plugin install git://github.com/rails/auto_complete.git

Para ver buenos ejemplos de como usar este plugin recomiendo ver el capítulo 102 en Railscasts.com y el ejemplo que D.H.H. puso aqui http://github.com/rails/auto_complete/tree/master

Ahi lo tienen.
Comentarios, preguntas, dudas e insultos son bienvenidos, dejen un mensaje.
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