12/08/2018, 13:45

Sử dụng gem Sorcery để gửi mail (P.2)

1. Giới thiệu Như ở phần trước, mình đã giới thiệu về chức năng khi tạo mới 1 user sẽ gửi mail để xác nhận tài khoản của gem Sorcery. Vậy khi sử dụng 1 thời gian, vào một ngày đẹp trời bạn bỗng quên password, vậy làm thế nào để bạn đăng nhập vào tài khoản thì ở bài viết này mình sẽ giới thiệu về ...

1. Giới thiệu

Như ở phần trước, mình đã giới thiệu về chức năng khi tạo mới 1 user sẽ gửi mail để xác nhận tài khoản của gem Sorcery. Vậy khi sử dụng 1 thời gian, vào một ngày đẹp trời bạn bỗng quên password, vậy làm thế nào để bạn đăng nhập vào tài khoản thì ở bài viết này mình sẽ giới thiệu về chức năng ResetPassword

2. Cài đặt

Cài gem trong gemfile, sau đó chạy lệnh

Sử dụng

    rails g sorcery:install reset_password --only-submodules

lênh này sẽ tạo ra

class SorceryResetPassword < ActiveRecord::Migration
  def change
    add_column :users, :reset_password_token, :string, :default => nil
    add_column :users, :reset_password_token_expires_at, :datetime, :default => nil
    add_column :users, :reset_password_email_sent_at, :datetime, :default => nil
  end
end

sau đó:

rake db:migrate

Vậy bước chuẩn bị để thêm những trường cần thiết cho chức năng reset password đã xong.

Tiếp theo, chúng ta tạo medthod reset_password_email (cái này để gửi mail khi mình muốn reset_password) bằng Sorcery nhé.

rails g mailer UserMailer reset_password_email
class UserMailer < ActionMailer::Base
  default from: "hehe@gmail.com"

  def reset_password_email(user)
    ...
  end
end

Đừng quên file config của sorcery nhé

# config/initializers/sorcery.rb
Rails.application.config.sorcery.submodules = [:reset_password, blabla, blablu, ...]

Rails.application.config.sorcery.configure do |config|
  config.user_config do |user|
    user.reset_password_mailer = UserMailer
  end
end

Chúng ta cần 1 controller để xử lý tất cả những action password

rails g controller PasswordResets create edit update

Sau 1 hồi biến đổi cải tạo thì nó sẽ trông như dưới đây

# app/controllers/password_resets_controller.rb
class PasswordResetsController < ApplicationController
  skip_before_filter :require_login

  # request password reset.
  # you get here when the user entered his email in the reset password form and submitted it.
  def create
    @user = User.find_by_email(params[:email])

    # This line sends an email to the user with instructions on how to reset their password (a url with a random token)
    @user.deliver_reset_password_instructions! if @user

    # Tell the user instructions have been sent whether or not email was found.
    # This is to not leak information to attackers about which emails exist in the system.
    redirect_to(root_path, :notice => 'Instructions have been sent to your email.')
  end

  # This is the reset password form.
  def edit
    @token = params[:id]
    @user = User.load_from_reset_password_token(params[:id])

    if @user.blank?
      not_authenticated
      return
    end
  end

  # This action fires when the user has sent the reset password form.
  def update
    @token = params[:id]
    @user = User.load_from_reset_password_token(params[:id])

    if @user.blank?
      not_authenticated
      return
    end

    # the next line makes the password confirmation validation work
    @user.password_confirmation = params[:user][:password_confirmation]
    # the next line clears the temporary token and updates the password
    if @user.change_password!(params[:user][:password])
      redirect_to(root_path, :notice => 'Password was successfully updated.')
    else
      render :action => "edit"
    end
  end
end

cài config/routes

resources :password_resets

nội dung mail

# app/views/user_mailer/reset_password_email.text.erb
Hello, <%= @user.email %>
===============================================

You have requested to reset your password.

To choose a new password, just follow this link: <%= @url %>.

Have a great day!
# app/mailers/user_mailer.rb
def reset_password_email(user)
  @user = User.find user.id
  @url  = edit_password_reset_url(@user.reset_password_token)
  mail(:to => user.email,
       :subject => "Your password has been reset")
end

ta tạo views của edit.html.erb của controller trên, đơn giản chỉ là form gửi đến action update của controller vừa tạo

# app/views/password_resets/edit.html.erb
<h1>Choose a new password</h1>
<%= form_for @user, :url => password_reset_path(@token), :html => {:method => :put} do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :email %><br />
    <%= @user.email %>
  </div>
  <div class="field">
    <%= f.label :password %><br />
    <%= f.password_field :password %>
  </div>
  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Cơ chế hoạt động như sau:

Khi click vào link "tôi thích reset password", sẽ gọi đến action create của controller vừa tạo, tiếp theo dựa vào lệnh "@user.deliver_reset_password_instructions! if @user" sorcery sẽ tạo 1 token và update vào user này đồng thời gửi mail với nội dung như trên.

Bạn vào mail, click vào đường link (method get) để có thể đến action edit => trên màn hình hiển thị form vừa tạo. Điền password, password_confirmation mới và sub mit để gọi đến action update (method put) tiến hành update cho @user.

3. Kết luận

Qua bài viết mình đã giới thiệu với các bạn về Sorcery một công cụ khá hữu ích với đủ các chức năng cần thiết đối với vấn đề về password, email của bạn. Hãy thử và cảm nhận sự tiện ích của nó đối với project của các bạn nhé.

4.

0