24、Rails 中实现邮件功能的详细指南

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
  1. 定义提醒方法 :在 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
  1. 创建提醒视图 :在 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
  1. 创建邮件控制器和提醒链接 :生成 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>
  1. 实现提醒表单和控制器操作 :创建提醒表单视图:
<!-- 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>
  1. 实现 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 %>
  1. 定义邮件消息方法和视图 :在 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 %>
  1. 测试双盲邮件系统 :为了测试邮件接口,需要创建第二个用户作为收件人,并在 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 项目中集成邮件功能提供有价值的参考,让你能够轻松实现各种邮件相关的需求。如果你在实践过程中遇到任何问题,欢迎留言交流。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值