Rails 中实现邮件功能的详细指南
在当今数字化的时代,邮件功能在各种应用程序中都扮演着至关重要的角色。无论是发送通知、找回密码还是用户之间的交流,邮件都是不可或缺的一部分。本文将详细介绍如何在 Rails 中实现邮件功能,包括配置、模板设置、发送方法以及测试等方面。
1. Action Mailer 基础
在 Rails 中,使用 Action Mailer 包可以轻松地实现邮件发送功能。Rails 将 MVC 架构应用到邮件处理中,其中 Action Mailer 类充当模型的角色。构建邮件消息时,需要为该消息定义一个方法,例如
reminder
方法,该方法会定义有效邮件消息所需的变量,如发件人、收件人和主题等。邮件的文本内容则是一个视图,通常定义在
.rhtml
文件中。借助这个方法和视图,Action Mailer 会合成一个与方法名对应的发送函数(例如
deliver_reminder
用于
reminder
操作),该函数可在控制器中根据用户输入来发送邮件。
2. 配置 Action Mailer
要发送邮件,首先需要对 Action Mailer 进行配置。默认配置使用 SMTP(简单邮件传输协议)来发送消息,并且可以自定义服务器设置。以下是一个示例配置:
# config/environment.rb
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.server_settings = {
:address => "smtp.example.com",
:port => 25,
:domain => "your_domain.com",
:authentication => :login,
:user_name => "your_user_name",
:password => "your_password",
}
你需要根据本地环境编辑服务器设置,通常需要使用你的 ISP 的 SMTP 服务器。例如,若使用 DSLExtreme(帕萨迪纳地区可用的 ISP),可以使用以下配置:
# config/environment.rb
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.server_settings = {
:address => "smtp.dslextreme.com",
:port => 25,
:domain => "railsspace.com"
}
此外,由于我们是在开发环境中发送邮件,为了在邮件发送出现问题时能看到错误信息,还需要编辑开发环境特定的配置文件:
# config/environments/development.rb
config.action_mailer.raise_delivery_errors = true
修改此文件后,需要重启 Web 服务器,这样系统就可以准备好发送邮件了。
3. 实现密码提醒功能
为了帮助忘记用户名或密码的用户,我们可以实现一个密码提醒功能。具体步骤如下:
1.
生成邮件发送器
:使用 Rails 提供的脚本生成
UserMailer
:
ruby script/generate mailer UserMailer
生成的
UserMailer
文件如下:
# app/models/user_mailer.rb
class UserMailer < ActionMailer::Base
end
-
定义提醒方法
:在
UserMailer类中创建reminder方法:
# app/models/user_mailer.rb
class UserMailer < ActionMailer::Base
def reminder(user)
@subject = 'Your login information at RailsSpace.com'
@body = {}
@body["user"] = user
@recipients = user.email
@from = 'RailsSpace <do-not-reply@railsspace.com>'
end
end
-
创建提醒视图
:在
app/views/user_mailer目录下创建reminder.rhtml文件:
<!-- app/views/user_mailer/reminder.rhtml -->
Hello,
Your login information is:
Screen name: <%= @user.screen_name %>
Password: <%= @user.password %>
--The RailsSpace team
-
创建邮件控制器和提醒链接
:生成
Email控制器和remind操作:
ruby script/generate controller Email remind
在登录页面添加提醒链接:
<!-- app/views/user/login.rhtml -->
<p>
Forgot your screen name or password?
<%= link_to "Remind Me!", :controller => "email", :action => "remind" %>
</p>
<p>
Not a member?
<%= link_to "Register now!", :action => "register" %>
</p>
- 实现提醒表单和控制器操作 :创建提醒表单视图:
<!-- app/views/email/remind.rhtml -->
<% form_for :user do |form| %>
<fieldset>
<legend><%= @title %></legend>
<div class="form_row">
<label for="email">Email:</label>
<%= form.text_field :email, :size => User::EMAIL_SIZE %>
</div>
<div class="form_row">
<%= submit_tag "Email Me!", :class => "submit" %>
</div>
</fieldset>
<% end %>
设置
Email
控制器中的
@title
:
# app/controllers/email_controller.rb
class EmailController < ApplicationController
def remind
@title = "Mail me my login information"
if param_posted?(:user)
email = params[:user][:email]
user = User.find_by_email(email)
if user
UserMailer.deliver_reminder(user)
flash[:notice] = "Login information was sent."
redirect_to :action => "index", :controller => "site"
else
flash[:notice] = "There is no user with that email address."
end
end
end
end
4. 测试密码提醒功能
在进行自动化测试之前,建议先手动进行测试。以
Foo Bar
身份登录,将电子邮件地址更改为你自己的地址,然后注销,通过登录页面导航到密码提醒页面并填写你的电子邮件地址。如果一切正常,提醒邮件应该会在几秒钟内出现在你的收件箱中。若未收到邮件,请仔细检查
config/environment.rb
中的配置,确保其与你的 ISP 设置相符。
自动化测试分为单元测试和功能测试:
-
单元测试
:对
UserMailer
进行单元测试,检查其属性是否正确:
# test/unit/user_mailer_test.rb
require File.dirname(__FILE__) + '/../test_helper'
require 'user_mailer'
class UserMailerTest < Test::Unit::TestCase
fixtures :users
FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
CHARSET = "utf-8"
include ActionMailer::Quoting
def setup
@user = users(:valid_user)
@expected = TMail::Mail.new
@expected.set_content_type "text", "plain", { "charset" => CHARSET }
end
def test_reminder
reminder = UserMailer.create_reminder(@user)
assert_equal 'do-not-reply@railsspace.com', reminder.from.first
assert_equal "Your login information at RailsSpace.com", reminder.subject
assert_equal @user.email, reminder.to.first
assert_match /Screen name: #{@user.screen_name}/, reminder.body
assert_match /Password: #{@user.password}/, reminder.body
end
private
def read_fixture(action)
IO.readlines("#{FIXTURES_PATH}/user_mailer/#{action}")
end
def encode(subject)
quoted_printable(subject, CHARSET)
end
end
-
功能测试
:对
Email控制器的remind操作进行功能测试:
# test/functional/email_controller_test.rb
require File.dirname(__FILE__) + '/../test_helper'
require 'email_controller'
# Re-raise errors caught by the controller.
class EmailController; def rescue_action(e) raise e end; end
class EmailControllerTest < Test::Unit::TestCase
fixtures :users
def setup
@controller = EmailController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@emails = ActionMailer::Base.deliveries
@emails.clear
@user = users(:valid_user)
# Make sure deliveries aren't actually made!
ActionMailer::Base.delivery_method = :test
end
def test_password_reminder
post :remind, :user => { :email => @user.email }
assert_response :redirect
assert_redirected_to :action => "index", :controller => "site"
assert_equal "Login information was sent.", flash[:notice]
assert_equal 1, @emails.length
end
end
5. 双盲邮件系统
为了让注册用户能够相互交流,我们将开发一个双盲邮件系统,该系统会保护发件人和收件人的电子邮件地址隐私。以下是实现步骤:
1.
添加邮件链接
:在每个用户的个人资料页面添加邮件链接,使用部分视图来封装逻辑:
<!-- app/views/profile/contact_box.rhtml -->
<% if logged_in? and @user != @logged_in_user %>
<div class="sidebar_box">
<h2>
<span class="header">Actions</span>
<br clear="all" />
</h2>
<ul>
<li><%= link_to "Email this user",
:controller => "email", :action => "correspond",
:id => @user.screen_name %></li>
</ul>
</div>
<% end %>
在
Profile
控制器的
show
方法中定义
@logged_in_user
变量:
# app/controllers/profile_controller.rb
def show
@hide_edit_links = true
screen_name = params[:screen_name]
@user = User.find_by_screen_name(screen_name)
@logged_in_user = User.find(session[:user_id]) if logged_in?
if @user
# ...
end
end
在个人资料页面中调用部分视图:
<!-- app/views/profile/show.rhtml -->
<div id="left_column">
<%= render :partial => 'avatar/sidebar_box' %>
<%= render :partial => 'contact_box' %>
<!-- ... -->
</div>
-
实现
correspond操作和邮件表单 :创建Message类来处理邮件消息:
# app/models/message.rb
class Message < ActiveRecord::Base
attr_accessor :subject, :body
validates_presence_of :subject, :body
validates_length_of :subject, :maximum => DB_STRING_MAX_LENGTH
validates_length_of :body, :maximum => DB_TEXT_MAX_LENGTH
def initialize(params)
@subject = params[:subject]
@body = params[:body]
end
end
在
Email
控制器中实现
correspond
操作:
# app/controllers/email_controller.rb
class EmailController < ApplicationController
include ProfileHelper
before_filter :protect, :only => [ "correspond" ]
def correspond
user = User.find(session[:user_id])
recipient = User.find_by_screen_name(params[:id])
@title = "Email #{recipient.name}"
if param_posted?(:message)
@message = Message.new(params[:message])
if @message.valid?
UserMailer.deliver_message(
:user => user,
:recipient => recipient,
:message => @message,
:user_url => profile_for(user),
:reply_url => url_for(:action => "correspond",
:id => user.screen_name)
)
flash[:notice] = "Email sent."
redirect_to profile_for(recipient)
end
end
end
end
创建邮件表单视图:
<!-- app/views/email/correspond.rhtml -->
<% form_for :message do |form| %>
<fieldset>
<legend><%= @title %></legend>
<%= error_messages_for 'message' %>
<div class="form_row">
<label for="subject">Subject:</label>
<%= form.text_field "subject", :size => 60 %>
</div>
<div class="form_row">
<label for="subject">Body:</label>
<%= form.text_area "body", :rows => 20, :cols => 60 %>
</div>
<%= submit_tag "Send", :class => "submit" %>
</fieldset>
<% end %>
-
定义邮件消息方法和视图
:在
UserMailer中定义message方法:
# app/models/user_mailer.rb
class UserMailer < ActionMailer::Base
def message(mail)
subject mail[:message].subject
from 'RailsSpace <do-not-reply@railsspace.com>'
recipients mail[:recipient].email
body mail
end
end
创建邮件消息视图:
<!-- app/views/user_mailer/message.rhtml -->
<%= @user.name %> at RailsSpace (<%= @user_url %>) writes:
<%= @message.body %>
To reply to this message, go to:
<%= @reply_url %>
-
测试双盲邮件系统
:为了测试邮件接口,需要创建第二个用户作为收件人,并在
users.yml和specs.yml中添加相关信息。
# test/fixtures/users.yml
friend:
id: 4
screen_name: amigo
email: ami@example.com
password: Freund
# Create 10 users so that searches can invoke pagination.
<% (1..10).each do |i| %>
user_<%= i %>:
id: <%= i + 4 %>
screen_name: user_<%= i %>
email: user_<%= i %>@example.com
password: foobar
<% end %>
# test/fixtures/specs.yml
friend_spec:
id: 3
user_id: 4
first_name: Dude
last_name: Dude
gender: Male
birthdate: 2000-01-01
occupation: Dude
city: Dude
state: CA
zip_code: 91125
在
UserMailer
测试文件中添加测试方法:
# test/unit/user_mailer_test.rb
class UserMailerTest < Test::Unit::TestCase
fixtures :users, :specs
def setup
@user = users(:valid_user)
@friend = users(:friend)
# ...
end
def test_message
user_url = "http://railsspace.com/profile/#{@user.screen_name}"
reply_url = "http://railsspace.com/email/correspond/#{@user.screen_name}"
message = Message.new(:subject => "Test message",
:body => "Dude, this is totally rad!")
email =
UserMailer.create_message(
:user => @user,
:recipient => @friend,
:message => message,
:user_url => user_url,
:reply_url => reply_url
)
assert_equal message.subject, email.subject
assert_equal @friend.email, email.to.first
assert_equal 'do-not-reply@railsspace.com', email.from.first
assert_match message.body, email.body
assert_match user_url, email.body
assert_match reply_url, email.body
end
# ...
end
在
Email
控制器功能测试中添加测试方法:
# test/functional/email_controller_test.rb
class EmailControllerTest < Test::Unit::TestCase
include ProfileHelper
fixtures :users, :specs
def setup
# ...
@user = users(:valid_user)
@friend = users(:friend)
# Make sure deliveries aren't actually made!
ActionMailer::Base.delivery_method = :test
end
def test_correspond
authorize @user
post :correspond, :id => @friend.screen_name,
:message => { :subject => "Test message",
:body => "Dude, this is totally rad!" }
assert_response :redirect
assert_redirected_to profile_for(@friend)
assert_equal "Email sent.", flash[:notice]
assert_equal 1, @emails.length
end
end
通过以上步骤,你可以在 Rails 中实现完整的邮件功能,包括密码提醒和用户间的双盲邮件交流。同时,通过编写单元测试和功能测试,可以确保系统的稳定性和可靠性。希望本文能帮助你顺利在 Rails 项目中集成邮件功能。
Rails 中实现邮件功能的详细指南
6. 总结与注意事项
在实现 Rails 邮件功能的过程中,我们完成了密码提醒和双盲邮件系统两个重要部分。以下是一些总结和注意事项:
6.1 配置方面
-
要根据本地环境准确配置 SMTP 服务器信息,如地址、端口、域名、用户名和密码等。若使用不同的 ISP,需相应修改配置文件
config/environment.rb中的内容。 -
在开发环境中,为了便于调试,要确保
config/environments/development.rb中config.action_mailer.raise_delivery_errors = true,修改后需重启 Web 服务器。
6.2 代码实现方面
- 在创建邮件发送器、控制器、视图等文件时,要遵循 Rails 的命名和目录结构规范,保证代码的可维护性。
-
在
UserMailer类中定义邮件方法时,要正确设置邮件的主题、发件人、收件人、正文等信息,同时利用@body传递数据到视图。 -
在控制器中处理邮件发送逻辑时,要进行必要的错误检查,如检查用户是否存在、邮件是否有效等,并通过
flash消息给用户反馈。
6.3 测试方面
- 手动测试可以作为初步验证邮件功能的手段,若手动测试未收到邮件,要检查配置文件。
-
单元测试和功能测试是保证系统稳定性的重要环节,要合理编写测试用例,覆盖各种可能的情况。在测试时,要注意设置
ActionMailer::Base.delivery_method = :test避免实际发送邮件。
7. 流程图
下面是双盲邮件系统的发送流程 mermaid 流程图:
graph LR
A[用户点击邮件链接] --> B[进入 correspond 操作]
B --> C{是否提交表单}
C -- 是 --> D[创建 Message 对象]
D --> E{Message 是否有效}
E -- 是 --> F[调用 UserMailer.deliver_message 发送邮件]
F --> G[显示邮件发送成功提示]
G --> H[重定向到收件人个人资料页面]
E -- 否 --> I[显示错误信息]
C -- 否 --> J[显示邮件表单]
8. 表格总结
| 功能模块 | 主要文件 | 关键代码 | 作用 |
|---|---|---|---|
| 密码提醒 |
app/models/user_mailer.rb
|
def reminder(user)
| 定义密码提醒邮件的内容和格式 |
app/views/user_mailer/reminder.rhtml
|
<%= @user.screen_name %>
等
| 显示密码提醒邮件的视图 | |
app/controllers/email_controller.rb
|
UserMailer.deliver_reminder(user)
| 处理密码提醒请求并发送邮件 | |
| 双盲邮件系统 |
app/models/message.rb
|
class Message < ActiveRecord::Base
| 处理邮件消息的验证和初始化 |
app/controllers/email_controller.rb
|
UserMailer.deliver_message
| 处理邮件发送请求并调用邮件发送方法 | |
app/views/email/correspond.rhtml
|
<% form_for :message do |form| %>
| 显示邮件表单 | |
app/models/user_mailer.rb
|
def message(mail)
| 定义双盲邮件的内容和格式 | |
app/views/user_mailer/message.rhtml
|
<%= @user.name %>
等
| 显示双盲邮件的视图 |
9. 总结
通过上述详细的步骤和代码示例,我们成功实现了在 Rails 中发送邮件的功能,包括密码提醒和双盲邮件系统。在实际应用中,你可以根据具体需求对这些功能进行扩展和优化,例如添加更多的邮件模板、支持 HTML 邮件格式等。同时,要重视测试工作,确保邮件功能的稳定性和可靠性,为用户提供良好的使用体验。
希望本文能为你在 Rails 项目中集成邮件功能提供有价值的参考,让你能够轻松实现各种邮件相关的需求。如果你在实践过程中遇到任何问题,欢迎留言交流。
超级会员免费看
47

被折叠的 条评论
为什么被折叠?



