Your SlideShare is downloading. ×
Sending Email with Rails
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Sending Email with Rails

7,755

Published on

This was the eight speech of a three day Rails training I gave in Tulsa, OK in the spring 2010.

This was the eight speech of a three day Rails training I gave in Tulsa, OK in the spring 2010.

Published in: Technology
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
7,755
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
174
Comments
0
Likes
6
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide























































































































  • Transcript

    • 1. Sending Email With Callbacks A look at ActionMailer and the ActiveRecord life cycle
    • 2. ActionMailer The email library that comes with Rails
    • 3. Mailers
    • 4. Mailers Mailers can be used to send email from Rails
    • 5. Mailers Mailers can be used to send email from Rails Supports plain text, HTML, and multi-part emails
    • 6. Mailers Mailers can be used to send email from Rails Supports plain text, HTML, and multi-part emails Supports attachments
    • 7. Mailers Mailers can be used to send email from Rails Supports plain text, HTML, and multi-part emails Supports attachments Multiple send modes including: sendmail and SMTP
    • 8. Mailers Mailers can be used to send email from Rails Supports plain text, HTML, and multi-part emails Supports attachments Multiple send modes including: sendmail and SMTP Mailers can also be used to receive emails
    • 9. Mailers Mailers can be used to send email from Rails Supports plain text, HTML, and multi-part emails Supports attachments Multiple send modes including: sendmail and SMTP Mailers can also be used to receive emails Parses the email data into a Ruby object
    • 10. M and V, Without the C
    • 11. M and V, Without the C Mailer structure is a bit different than other parts of Rails
    • 12. M and V, Without the C Mailer structure is a bit different than other parts of Rails It’s a model
    • 13. M and V, Without the C Mailer structure is a bit different than other parts of Rails It’s a model But it has views
    • 14. M and V, Without the C Mailer structure is a bit different than other parts of Rails It’s a model But it has views You can think of it as rendering content for the user, just not through a browser
    • 15. Email Example
    • 16. Email Example Let’s say I have an application built that requires users to login to see any content
    • 17. Email Example Let’s say I have an application built that requires users to login to see any content I have created a User model and built the controller that allows them to sign-up
    • 18. Email Example Let’s say I have an application built that requires users to login to see any content I have created a User model and built the controller that allows them to sign-up I have also wired up a login system using Authlogic
    • 19. Email Example Let’s say I have an application built that requires users to login to see any content I have created a User model and built the controller that allows them to sign-up I have also wired up a login system using Authlogic The whole thing works now
    • 20. A Problem
    • 21. A Problem I really need to make sure users give me a valid email
    • 22. A Problem I really need to make sure users give me a valid email Authlogic checks the email address format, but you can only know an email is valid by sending a message
    • 23. Adding Authentication
    • 24. Adding Authentication When a user signs up:
    • 25. Adding Authentication When a user signs up: We will send them an email with a special link in it
    • 26. Adding Authentication When a user signs up: We will send them an email with a special link in it Clicking that link will authenticate their address
    • 27. Adding Authentication When a user signs up: We will send them an email with a special link in it Clicking that link will authenticate their address We won’t allow non-authenticated users access to the site
    • 28. Adding Authentication When a user signs up: We will send them an email with a special link in it Clicking that link will authenticate their address We won’t allow non-authenticated users access to the site After authentication, their account will work normally
    • 29. Generate a Mailer
    • 30. Generate a Mailer We call script/ generate as usual $ ruby script/generate mailer user_notifier activation exists app/models/ create app/views/user_notifier exists test/unit/ create test/fixtures/user_notifier create app/models/user_notifier.rb create test/unit/user_notifier_test.rb create app/views/user_notifier/activation.erb create test/fixtures/user_notifier/activation
    • 31. Generate a Mailer We call script/ generate as usual We ask for a mailer $ ruby script/generate mailer user_notifier activation exists app/models/ and name it create app/views/user_notifier exists test/unit/ create test/fixtures/user_notifier user_notifier create app/models/user_notifier.rb create test/unit/user_notifier_test.rb create app/views/user_notifier/activation.erb create test/fixtures/user_notifier/activation
    • 32. Generate a Mailer We call script/ generate as usual We ask for a mailer $ ruby script/generate mailer user_notifier activation exists app/models/ and name it create app/views/user_notifier exists test/unit/ create test/fixtures/user_notifier user_notifier create app/models/user_notifier.rb create test/unit/user_notifier_test.rb create app/views/user_notifier/activation.erb create test/fixtures/user_notifier/activation Optionally, we can also pass the names of emails to create
    • 33. app/models/user_notifier.rb The generated mailer gets us started
    • 34. class UserNotifier < ActionMailer::Base def activation(sent_at = Time.now) subject 'UserNotifier#activation' recipients '' from '' sent_on sent_at body :greeting => 'Hi,' end end app/models/user_notifier.rb The generated mailer gets us started
    • 35. class UserNotifier < ActionMailer::Base def activation(sent_at = Time.now) subject 'UserNotifier#activation' recipients '' from '' sent_on sent_at body :greeting => 'Hi,' end end app/models/user_notifier.rb The generated mailer gets us started
    • 36. class UserNotifier < ActionMailer::Base def activation(sent_at = Time.now) subject 'UserNotifier#activation' recipients '' from '' sent_on sent_at body :greeting => 'Hi,' end end app/models/user_notifier.rb The generated mailer gets us started
    • 37. class UserNotifier < ActionMailer::Base def activation(sent_at = Time.now) subject 'UserNotifier#activation' recipients '' from '' sent_on sent_at body :greeting => 'Hi,' end end app/models/user_notifier.rb The generated mailer gets us started
    • 38. class UserNotifier < ActionMailer::Base def activation(sent_at = Time.now) subject 'UserNotifier#activation' recipients '' from '' sent_on sent_at body :greeting => 'Hi,' end end app/models/user_notifier.rb The generated mailer gets us started
    • 39. Customized to our Needs We will work with a User since that makes sense for what we are trying to do
    • 40. class UserNotifier < ActionMailer::Base def activation(user) subject 'Activate Your Account' recipients user.email from 'admin@secureapp.com' sent_on Time.now body :user => user end end Customized to our Needs We will work with a User since that makes sense for what we are trying to do
    • 41. class UserNotifier < ActionMailer::Base def activation(user) subject 'Activate Your Account' recipients user.email from 'admin@secureapp.com' sent_on Time.now body :user => user end end Customized to our Needs We will work with a User since that makes sense for what we are trying to do
    • 42. class UserNotifier < ActionMailer::Base def activation(user) subject 'Activate Your Account' recipients user.email from 'admin@secureapp.com' sent_on Time.now body :user => user end end Customized to our Needs We will work with a User since that makes sense for what we are trying to do
    • 43. class UserNotifier < ActionMailer::Base def activation(user) subject 'Activate Your Account' recipients user.email from 'admin@secureapp.com' sent_on Time.now body :user => user end end Customized to our Needs We will work with a User since that makes sense for what we are trying to do
    • 44. The Email Content This is the code from app/views/user_notifier/activation.erb
    • 45. Welcome to the Secure Application. Please click the following link to activate your account: <%= activate_url(:token => @user.perishable_token, :host => "localhost:3000") %> The Email Content This is the code from app/views/user_notifier/activation.erb
    • 46. Welcome to the Secure Application. Please click the following link to activate your account: <%= activate_url(:token => @user.perishable_token, :host => "localhost:3000") %> The Email Content This is the code from app/views/user_notifier/activation.erb
    • 47. Welcome to the Secure Application. Please click the following link to activate your account: <%= activate_url(:token => @user.perishable_token, :host => "localhost:3000") %> The Email Content This is the code from app/views/user_notifier/activation.erb
    • 48. Welcome to the Secure Application. Please click the following link to activate your account: <%= activate_url(:token => @user.perishable_token, :host => "localhost:3000") %> The Email Content This is the code from app/views/user_notifier/activation.erb
    • 49. Sending an Email
    • 50. Sending an Email You can send an email from anywhere in the application
    • 51. Sending an Email You can send an email from anywhere in the application UserNotifier.deliver_activation(user) Just call deliver_EMAIL() where EMAIL is the name of the message
    • 52. Mailers in Production
    • 53. Mailers in Production By default, ActionMailer will try to use sendmail to deliver emails in production
    • 54. Mailers in Production By default, ActionMailer will try to use sendmail to deliver emails in production This works on a lot of servers but is not robust
    • 55. Mailers in Production By default, ActionMailer will try to use sendmail to deliver emails in production This works on a lot of servers but is not robust I recommend setting up a Gmail account and configuring ActionMailer to send via SMTP
    • 56. Mailers in Production By default, ActionMailer will try to use sendmail to deliver emails in production This works on a lot of servers but is not robust I recommend setting up a Gmail account and configuring ActionMailer to send via SMTP You may also wish to shut off ActionMailer’s default error raising behavior
    • 57. Callbacks Taking actions during the ActiveRecord life cycle
    • 58. The ActiveRecord Life Cycle
    • 59. The ActiveRecord Life Cycle Models have a life cycle
    • 60. The ActiveRecord Life Cycle Models have a life cycle They are created
    • 61. The ActiveRecord Life Cycle Models have a life cycle They are created Read from the database
    • 62. The ActiveRecord Life Cycle Models have a life cycle They are created Read from the database Updated
    • 63. The ActiveRecord Life Cycle Models have a life cycle They are created Read from the database Updated Destroyed
    • 64. The ActiveRecord Life Cycle Models have a life cycle They are created Read from the database Updated Destroyed Callbacks allow us to run code at points in this cycle
    • 65. The Callback Hooks
    • 66. The Callback Hooks after_initialize*
    • 67. The Callback Hooks after_initialize* before_save
    • 68. The Callback Hooks after_initialize* before_save before_create/update
    • 69. The Callback Hooks after_initialize* before_save before_create/update before_validation
    • 70. The Callback Hooks after_initialize* before_save before_create/update before_validation before_validation_on_ create/update
    • 71. The Callback Hooks after_initialize* before_save before_create/update before_validation before_validation_on_ create/update after_validation
    • 72. The Callback Hooks after_initialize* after_validation_on_cr eate/update before_save before_create/update before_validation before_validation_on_ create/update after_validation
    • 73. The Callback Hooks after_initialize* after_validation_on_cr eate/update before_save after_save before_create/update before_validation before_validation_on_ create/update after_validation
    • 74. The Callback Hooks after_initialize* after_validation_on_cr eate/update before_save after_save before_create/update after_create/update before_validation before_validation_on_ create/update after_validation
    • 75. The Callback Hooks after_initialize* after_validation_on_cr eate/update before_save after_save before_create/update after_create/update before_validation after_find* before_validation_on_ create/update after_validation
    • 76. The Callback Hooks after_initialize* after_validation_on_cr eate/update before_save after_save before_create/update after_create/update before_validation after_find* before_validation_on_ create/update before_destroy after_validation
    • 77. The Callback Hooks after_initialize* after_validation_on_cr eate/update before_save after_save before_create/update after_create/update before_validation after_find* before_validation_on_ create/update before_destroy after_validation after_destroy
    • 78. Building a Callback Just choose the type of callback, name a method, and write a matching Ruby method
    • 79. class User < ActiveRecord::Base acts_as_authentic after_create :send_activation_email def send_activation_email reset_perishable_token! UserNotifier.deliver_activation(self) end end Building a Callback Just choose the type of callback, name a method, and write a matching Ruby method
    • 80. class User < ActiveRecord::Base acts_as_authentic after_create :send_activation_email def send_activation_email reset_perishable_token! UserNotifier.deliver_activation(self) end end Building a Callback Just choose the type of callback, name a method, and write a matching Ruby method
    • 81. class User < ActiveRecord::Base acts_as_authentic after_create :send_activation_email def send_activation_email reset_perishable_token! UserNotifier.deliver_activation(self) end end Building a Callback Just choose the type of callback, name a method, and write a matching Ruby method
    • 82. class User < ActiveRecord::Base acts_as_authentic after_create :send_activation_email def send_activation_email reset_perishable_token! UserNotifier.deliver_activation(self) end end Building a Callback Just choose the type of callback, name a method, and write a matching Ruby method
    • 83. Not Just for Email
    • 84. Not Just for Email Sending email using callbacks is a common usage
    • 85. Not Just for Email Sending email using callbacks is a common usage However, callbacks are a general tool with many uses
    • 86. Not Just for Email Sending email using callbacks is a common usage However, callbacks are a general tool with many uses For example:
    • 87. Not Just for Email Sending email using callbacks is a common usage However, callbacks are a general tool with many uses For example: You might update an average_review_rating column with an after_save on Review
    • 88. Not Just for Email Sending email using callbacks is a common usage However, callbacks are a general tool with many uses For example: You might update an average_review_rating column with an after_save on Review You might generate a login column from a provided email address in a before_validation on User
    • 89. Completing the Example We need to make some minor changes and add a controller to get activation working
    • 90. Migrating in Activation Fields Rails migrations are pretty smart and can guess where you want to add the fields
    • 91. $ ruby script/generate migration add_activation_fields_to_users perishable_token:string active:boolean Migrating in Activation Fields Rails migrations are pretty smart and can guess where you want to add the fields
    • 92. $ ruby script/generate migration add_activation_fields_to_users perishable_token:string active:boolean Migrating in Activation Fields Rails migrations are pretty smart and can guess where you want to add the fields
    • 93. $ ruby script/generate migration add_activation_fields_to_users perishable_token:string active:boolean Migrating in Activation Fields Rails migrations are pretty smart and can guess where you want to add the fields
    • 94. $ ruby script/generate migration add_activation_fields_to_users perishable_token:string active:boolean class AddActivationFieldsToUsers < ActiveRecord::Migration def self.up add_column :users, :perishable_token, :string add_column :users, :active, :boolean, :default => false, :null => false end def self.down remove_column :users, :active remove_column :users, :perishable_token end end Migrating in Activation Fields Rails migrations are pretty smart and can guess where you want to add the fields
    • 95. $ ruby script/generate migration add_activation_fields_to_users perishable_token:string active:boolean class AddActivationFieldsToUsers < ActiveRecord::Migration def self.up add_column :users, :perishable_token, :string add_column :users, :active, :boolean, :default => false, :null => false end def self.down remove_column :users, :active remove_column :users, :perishable_token end end Migrating in Activation Fields Rails migrations are pretty smart and can guess where you want to add the fields
    • 96. $ ruby script/generate migration add_activation_fields_to_users perishable_token:string active:boolean class AddActivationFieldsToUsers < ActiveRecord::Migration def self.up add_column :users, :perishable_token, :string add_column :users, :active, :boolean, :default => false, :null => false end def self.down remove_column :users, :active remove_column :users, :perishable_token end end $ rake db:migrate Migrating in Activation Fields Rails migrations are pretty smart and can guess where you want to add the fields
    • 97. Adding Activations We look the user up by token, activate them, and log them in
    • 98. $ ruby script/generate controller activations Adding Activations We look the user up by token, activate them, and log them in
    • 99. $ ruby script/generate controller activations class ActivationsController < ApplicationController def create if @user = User.find_using_perishable_token(params[:token]) @user.active = true # activate the user @user.save UserSession.create(@user) # log them in flash[:notice] = "User activated." else flash[:error] = "User not found." end redirect_to root_path end end Adding Activations We look the user up by token, activate them, and log them in
    • 100. $ ruby script/generate controller activations class ActivationsController < ApplicationController def create if @user = User.find_using_perishable_token(params[:token]) @user.active = true # activate the user @user.save UserSession.create(@user) # log them in flash[:notice] = "User activated." else flash[:error] = "User not found." end redirect_to root_path end end Adding Activations We look the user up by token, activate them, and log them in
    • 101. $ ruby script/generate controller activations class ActivationsController < ApplicationController def create if @user = User.find_using_perishable_token(params[:token]) @user.active = true # activate the user @user.save UserSession.create(@user) # log them in flash[:notice] = "User activated." else flash[:error] = "User not found." end redirect_to root_path end end Adding Activations We look the user up by token, activate them, and log them in
    • 102. $ ruby script/generate controller activations class ActivationsController < ApplicationController def create if @user = User.find_using_perishable_token(params[:token]) @user.active = true # activate the user @user.save UserSession.create(@user) # log them in flash[:notice] = "User activated." else flash[:error] = "User not found." end redirect_to root_path end end Adding Activations We look the user up by token, activate them, and log them in
    • 103. Email Routing We can’t make an email link POST, so I created a custom route for the action
    • 104. ActionController::Routing::Routes.draw do |map| map.resources :users map.resource :user_session map.login "login", :controller => "user_sessions", :action => "new" map.logout "logout", :controller => "user_sessions", :action => "destroy" map.activate "activate/:token", :controller => "activations", :action => "create" map.root :controller => "home" map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end Email Routing We can’t make an email link POST, so I created a custom route for the action
    • 105. ActionController::Routing::Routes.draw do |map| map.resources :users map.resource :user_session map.login "login", :controller => "user_sessions", :action => "new" map.logout "logout", :controller => "user_sessions", :action => "destroy" map.activate "activate/:token", :controller => "activations", :action => "create" map.root :controller => "home" map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end Email Routing We can’t make an email link POST, so I created a custom route for the action
    • 106. The Old Sign-up Our old controller logs them in as they are created and we can’t have that
    • 107. class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save flash[:notice] = "Welcome!" redirect_to root_path else flash.now[:error] = "Sign-up could not be completed." render :action => :new end end end The Old Sign-up Our old controller logs them in as they are created and we can’t have that
    • 108. class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save flash[:notice] = "Welcome!" redirect_to root_path else flash.now[:error] = "Sign-up could not be completed." render :action => :new end end end The Old Sign-up Our old controller logs them in as they are created and we can’t have that
    • 109. class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save flash[:notice] = "Welcome!" redirect_to root_path else flash.now[:error] = "Sign-up could not be completed." render :action => :new end end end The Old Sign-up Our old controller logs them in as they are created and we can’t have that
    • 110. Creation Without Login Now we don’t log them in and we tell them to check their email
    • 111. class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save_without_session_maintenance flash[:notice] = "Please check your email to activate your account." redirect_to login_path else flash.now[:error] = "Sign-up could not be completed." render :action => :new end end end Creation Without Login Now we don’t log them in and we tell them to check their email
    • 112. class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save_without_session_maintenance flash[:notice] = "Please check your email to activate your account." redirect_to login_path else flash.now[:error] = "Sign-up could not be completed." render :action => :new end end end Creation Without Login Now we don’t log them in and we tell them to check their email
    • 113. class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save_without_session_maintenance flash[:notice] = "Please check your email to activate your account." redirect_to login_path else flash.now[:error] = "Sign-up could not be completed." render :action => :new end end end Creation Without Login Now we don’t log them in and we tell them to check their email
    • 114. Activations in Action Let’s see what we have created
    • 115. Signing Up I can create a new user with my email address and desired password
    • 116. Signing Up I can create a new user with my email address and desired password
    • 117. Time to Check Email I wasn’t logged in, as planned
    • 118. Time to Check Email I wasn’t logged in, as planned
    • 119. Can’t Login Yet I can’t login yet either, since my account isn’t active yet
    • 120. Can’t Login Yet I can’t login yet either, since my account isn’t active yet
    • 121. log/development.rb In development mode, emails are printed to the log file (clear logs with: rake log:clear)
    • 122. Sent mail to james@graysoftinc.com Date: Sun, 7 Mar 2010 15:10:11 -0600 From: admin@secureapp.com To: james@graysoftinc.com Subject: Activate Your Account Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Welcome to the Secure Application. Please click the following link to activate your account: http://localhost:3000/activate/5HkeFFwiInKfjA4x25q9 log/development.rb In development mode, emails are printed to the log file (clear logs with: rake log:clear)
    • 123. Activated and Logged In Visiting the URL completes the process
    • 124. Activated and Logged In Visiting the URL completes the process
    • 125. Questions?
    • 126. User Emails Lab Your book has instructions for how to add email notifications to your application

    ×