ActionMailer in Ruby On Rails
Bài đăng này đã không được cập nhật trong 7 năm
I. Giới thiệu.
ActionMailer trong Rails cho phép bạn gửi email từ ứng dụng của bạn thông qua class mailer và views. ActionMailer về cơ bản hoạt động cũng giống như ta xây dựng một controller và định nghĩa các action và view tương ứng. Nó được kế thừa từ lớp ActionMailer::Base và được đặt mặc định trong thư mục app/mailers và lớp views cũng nằm trong thư mục app/views.
II. Gửi email bằng ActionMailer.
Trong phần này chúng ta sẽ xây dựng một app với một vài chức năng mà tôi tin hầu hết các ứng dụng web bây giờ đều cần đến, đó là cho User tạo tài khoản của hệ thống bằng địa chỉ email, và sau đó xác thực địa chỉ email bằng việc để hệ thống tự động gửi email đến tài khoản email của User, kèm một confirm_token để xác thực.
1. Việc đầu tiên là tạo ứng dụng demo.
rails new demo_app
Sau đó tạo model User:
rails g model User mail_address password_digest confirm_token confirmed_at:datetime
Trong gem file, ta thêm "gem 'bcrypt', '~> 3.1.7'", "gem 'sidekiq'", "gem 'redis-namespace'".
Và bước tiếp theo là cần cài đặt thuộc tính, các function trong class user, trong app/models/user.rb
ta cài đặt như sau:
class User < ActiveRecord::Base
PARAMS_SIGNUP = [:mail_address, :password, :password_confirmation]
EMAIL_REGEX = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
validates :mail_address, format: {with: EMAIL_REGEX}, uniqueness: true, presence: true
validates :password, presence: true, length: {minimum: 6, maximum: 20}
before_create :generate_confirm_token
has_secure_password
scope :confirmed, ->{where "`users`.`confirm_token` IS NULL AND `users`.`confirmed_at` < ?", Time.now}
def reset_confirm_token
generate_confirm_token
self.save
end
private
def generate_token column
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
def generate_confirm_token
generate_token :confirm_token
end
end
Để ý dòng scope :confirmed, ->{where "
users.
confirm_tokenIS NULL AND
users.
confirmed_at< ?", Time.now}
, ta định nghĩa một scope confirmed ở đây để chỉ ra các tài khoản đã xác thực mail_address.
Sau đó chúng ta cần tạo controller và view của User để có được giao diện signup:
rails g controller Users
Ta tiếp tục cài đặt các hàm và các view tương ứng, đầu tiên là trang signup và trang chuyển đến sau khi tài khoản được tạo với nội dung thông báo cho người dùng phải xác thực tài khoản email. Trong app/contrrollers/users_controller.rb ta cài đặt các action sau:
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new user_signup_params
if @user.save
redirect_to check_mail_address_path
else
render :new
end
end
def check_mail_address
end
private
def user_signup_params
params.require(:user).permit(User::PARAMS_SIGNUP)
end
end
Tạo các view, trong app/views/users tạo view "new.html.erb":
<%= form_for @user do |f| %>
<%= f.label :mail_address, "Email"%>
<%= f.text_field :mail_address %> <br>
<%= f.label :mail_address, "Password"%>
<%= f.password_field :password %> <br>
<%= f.label :mail_address, "Password confirmation"%>
<%= f.password_field :password_confirmation %><br>
<%= f.submit "Submit"%>
<% end %>
Tiếp tục tạo view của trang chuyển đến, thông báo cho người dùng phải xác thực mail_address sau khi signup: tạo view "check_mail_address.html.erb" trong app/views/users
We sent an email to your mail address, please check !
Trong config/routes.rb ta tạo các route để có đường link /signup , /check_mail_address :
Rails.application.routes.draw do
get "/signup", to: "users#new"
post "/signup", to: "users#create"
get "check_mail_address", to: "users#check_mail_address"
resources :users
end
2. Gửi email xác thực người dùng.
Bây giờ ta bắt đầu nói đến việc gửi email cho người dùng. Trước hết tôi xin giải thích flow mà chúng ta đã làm được 1/2 ở trên. Đầu tiên User vào trang signup, tạo tài khoản, điền đầy đủ thông tin vào sau đó submit form, lúc này tài khoản của người dùng đã có trong database nhưng sau đó, hệ thống của chúng ta cần gửi email cho ngươi dùng để xác thực email đó là email thật, không phải email giả, bằng một đường link kèm theo confirm_token mà đã được tạo ra bằng phương thưc call_back ở trong model "user.rb" đó là:
before_create :generate_confirm_token
Và sau khi người dùng click vào link đó thì hệ thống sẽ xử lí việc xác thực thông qua confirm_token, và chuyển đến trang "/signup_success". Giờ ta sẽ tạo một class mailer để xử lí việc đó:
rails g mailer UserMailer
Trong "app/mailers/user_mailer.rb" ta cài đặt action "confirm_user_mail" như sau:
class UserMailer < ApplicationMailer
def confirm_user_mail user
@user ||= user
mail(to: user.mail_address, subject: "Confirm Your Account") if user.mail_address?
end
end
Tiếp đó trong "app/views/user_mailer" ta tạo file "confirm_user_mail.html.erb" với nội dung:
<p>Welcome</p> <% @user.mail_address %> <p>to Framgia</p>
<%= link_to "Confirm Account", confirm_mail_address_user_url(@user.confirm_token) %>
Sau đó ta cần config lại file "config/environments/development.rb", thêm một số dòng để có thể sử dụng được ActionMailer:
config.action_mailer.default_url_options = {:host => "localhost:3000"}
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_caching = false
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
domain: "gmail.com",
authentication: "plain",
enable_starttls_auto: true,
user_name: ENV["GMAIL_USERNAME"],
password: ENV["GMAIL_PASSWORD"]
}
GMAIL_USERNAME ở đây là địa chỉ gmail của bạn, còn GMAIL_PASSWORD là mật khẩu tài khoản gmail của bạn. Tiếp theo, ta cần 1 function để xác thực confirm_token của người dùng trong "users_controller.rb", và nếu xác thực thành công, cần chuyển sang 1 trang signup_success, còn nếu không chuyển sang trang signup_fail. Thêm vào app/controllers/users_controller.rb :
def confirm_mail_address
@user = User.find_by confirm_token: params[:id]
if @user
@user.update confirm_token: nil, confimed_at: Time.now
redirect_to signup_success_path
else
redirect_to signup_fail_path
end
end
def signup_success
end
def signup_fail
end
Thêm vào app/views/users file "signup_success.html.erb":
Singup success, please login!
Và file "signup_fail.html.erb":
Signup fail !
Sau đó cần chỉnh lại config/routes.rb :
get "/signup_success", to: "users#signup_success"
get "/signup_fail", to: "users#signup_fail"
resources :users do
put :confirm_mail_address, on: :member
end
end
Để cho hệ thống tự động gửi mail vào địa chỉ mail của người dùng sau khi người đó tạo tài khoản, ta cần có 1 hàm gửi mail được gọi sau khi User được tạo. Thêm vào file "app/models/user.rb":
class User < ActiveRecord::Base
PARAMS_SIGNUP = [:mail_address, :password, :password_confirmation]
EMAIL_REGEX = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
validates :mail_address, format: {with: EMAIL_REGEX}, uniqueness: true, presence: true
validates :password, presence: true, length: {minimum: 6, maximum: 20}
before_create :generate_confirm_token
after_create :confirm_mail_address
has_secure_password
scope :confirmed, ->{where "`users`.`confirm_token` IS NULL AND `users`.`confirmed_at` < ?", Time.now}
def reset_confirm_token
generate_confirm_token
self.save
end
private
def generate_token column
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
def generate_confirm_token
generate_token :confirm_token
end
def confirm_mail_address
UserMailer.confirm_user_mail(self).deliver_now
end
end
Ta sẽ gọi đến hàm confirm_mail_address sau khi User được tạo bằng call_back "after_create". Giờ thì bật server local lên và check thử thôi các bạn, đừng quên bật sidekiq cho việc gửi mail nhé
All rights reserved