Bài toán gửi mail chúc mừng sinh nhật dưới dạng background job trong Rails?

697

Người viết: Hiếu Hoàng Trọng

Ngày mình mới nhận câu hỏi:

Lúc đầu mình thấy game này dễ, làm vài tiếng chắc là xong. Thôi bỏ đấy đi chơi, tuần này còn phải xem Dissneeland 7, tuần sau rồi làm, mình để deadline tận một tuần cơ mà. Sang tuần, bắt tay vào giải quyết vấn đề được một ngày thì:

Sau khi xác định lại bài toán, vật lộn thêm tổng cộng 2 ngày thì cũng xong.

Đấy , nên chốt lại là ở bài này, chúng ta sẽ cùng nhau giải quyết bài toán gửi mail chúc mừng sinh nhật khách hàng, từ đó giải thích cho Nhật Vy hiểu được 2 vấn đề:

  • Cách mà AcionMailer hoạt động.
  • Cách gửi mail dưới dạng background job thông qua việc sử dụng ActiveJob và Sidekiq.

Có thể bạn quan tâm

16 lời khuyên để tạo Form Đăng Ký và Đăng Nhập có UX tốt

Responsive HTML bằng một dòng CSS

I. Sử dụng ActionMailer để gửi mail trong Rails application?

Phần này mình sẽ trình bày một số khái niệm, cách cấu hình để chúng ta giải quyết một bài toán cơ bản:

Bài toán 1: Mỗi khi user đăng nhập, ta gửi một email chào mừng đến hòm thư của user (ở đây mình dùng gmail)

1. Mailer là gì, cách khởi tạo?

Chúng ta đều thấy mỗi khi ta tạo một rails app bằng macro rails new app_name, nó sẽ tự động làm một loạt các hành động khó hiểu, nhưng cái chúng ta quan tâm nhất thường là thư mục app .

Khi mới học lập trình với rails ở mức độ cơ bản, chúng ta thường chỉ quan tâm đến controllerassets , views , helper. Còn trong bài viết ngày hôm nay, mình sẽ giải thích cho các bạn và Nhật Vy hiểu thêm về mailer và job, xem hai thư mục này dùng để chứa những thứ gì.

Đầu tiên, thư mục mailer chứa những thứ gì? . Nó đơn giản là tập hợp của các class kế thừa từ ActionMailer::Base , ví dụ:

Các mailer có nhiều điểm tương đồng với các controller , chúng ta có thể tạo ra mailer bằng macro :

Như chúng ta đã thấy, macro này tạo ra một class mailer (có thể là hai nếu application_mailer.rb chưa tồn tại) , một thư mục views và một thư mục test giống như cách mà controllerđược tạo ra. Ngoài ra, tất nhiên chúng ta có thể tạo mailertheo cách thủ công – tạo một class kế thừa ActionMailer::Base (Hoặc ApplicationMailer )

2. Edit mailer

Tạo được mailer rồi, bây giờ chúng ta cần thêm vào vài dòng code đủ để mailer thực hiện đúng vai trò của nó. Đầu tiên, chúng ta cùng tạo ra một method welcome_email

Ở đây, chúng ta cần chú ý đến method mail . Tham số của method này là một hashchứa các giá trị trong thông điệp mà email truyền tải, ví dụ như subject: , date:content-type:, ….. Để một email được gửi, chúng ta tối thiểu phải set được hai giá trị tương ứng với hai key:

  • to: email của người nhận.
  • from: Tên của người gửi. Nếu một trong hai key này không được set value , mail sẽ không được gửi. Các bạn không nhất thiết phải set các giá trị này ở đằng sau method mail, có thể set nó ở default hash cũng được. Ví dụ:

Chỉ khác là, default hash chứa các giá trị mặc định. Nếu ở sau method mail các giá trị này không được set, thì Rails sẽ lấy giá trị của default hash để thay thế.

3. Edit views

Cách mailer render view cũng khá giống controller. Ở trong Mailer, các method cũng được gọi là action. Mặc định khi thực hiện một action trong mailer , view được render để gửi đi sẽ có cùng tên với action . Tức là với actionUserMailer#welcome_emailRails sẽ tìm đến file views/user_mailer/welcome_email.html.erb để render . Vậy ta cùng tạo một file welcome_email.html.erb như sau:

Đó thế là xong cái views.

4. Cấu hình biến môi trường với gem figaro.

Để gửi được email từ Mailer, chúng ta phải có cấu hình một hộp thư điện tử dành riêng cho ứng dụng(ở đây mình sử dụng gmail). Từ đó, ứng dụng của chúng ta có thể tự động đăng nhập và gửi thư từ hộp thư được cung cấp. Để làm được điều này, chúng ta phải cấu hình một số biến môi trường chứa các thông tin cần được bảo mật – cụ thể như “username” và “password” của tài khoản gmail. Công việc này vốn là khá phức tạp, nhưng với sự xuất hiện của gem figaro mọi chuyện trở lên đơn giản hơn nhiều. Đầu tiên, các bạn cần thêm vào Gemfile

sau đó chạy bundle exec figaro install . Điều này tương tự với việc một file application.yml được tạo và được bỏ vào .gitignore . Sau đó, trong file application.yml bạn cấu hình như này:

Bạn có thể kiểm tra trong log xem biến mỗi trường của bạn đã được cài đặt chưa. Nào cùng rails c một cái:

Và bước cuối cùng, cấu hình file application.rb

Xong thì nhớ reset lại server nhé!.

5, Gửi mail thôi!

Gửi mail là một bước vô cùng đơn giản, bạn chỉ cần đặt được câu lệnh dưới đây vào bất kỳ nơi nào mà nó có thể chạy được. Nhanh nhất là để nó ở trong Rails console

Và cùng xem cách nó chạy:

Ú ù, nó có cái lỗi gì kỳ thế nhỉ. Sau khi check lại đoạn Exception mình đã nhận ra một dòng code có vấn đề ở trong controller .

Cụ thể cái Exception NoMethodError (undefined method "[]" for nil:NilClass) muốn nói với chúng ta rằng, params hiện tại không có gì hết ( nil ) . Đến đây chúng ta sẽ có một câu hỏi khá thú vị , đó là :

Làm sao để truyền được các giá trị vào params trước khi nhảy đến action trong Mailer ?

Trước khi nhảy đến controller , trong views chúng ta có thể dùng các form helper để truyền giá trị vào params . Còn đối với mailer, mình mới chỉ tìm ra một cách, đó là sử dụng class method with . Cụ thể nếu chúng ta muốn truyền params[:user] = User.first , có thể truyền như sau:

Và cùng xem cách nó chạy:

Mail cũng đã đến được hộp thư của mình rồi nè:

Giờ thì chúng ta cùng nhớ về bài toán mình đặt ra ở đầu bài, đó là “Mỗi khi người dùng đăng nhập, chúng ta sẽ gửi một email chào mừng”. Thế thì bước cuối cùng để giải quyết bài toán này chính là tìm ra vị trí để đặt dòng lệnh dưới đây: (gọi nó là dòng lệnh (1) )

Vị trí đặt dòng lệnh (1) của chúng ta phải là nơi mà đáp ứng được hai điều kiện:

  • Nơi mà session đã được create ( log_in thành công)
  • Nơi mà chúng ta có thể truyền được current_user ( hoặc một biến nào đó có giá trị là user vừa đăng nhập)

Đến đây cũng tùy vào việc các bạn làm chức năng log_in như thế nào, thường là có hai cách làm chức năng log_in với rails :

  • Tự tạo sessions_controller
  • Sử dụng gem devise

Với cách đầu tiên thì quá đơn giản vì các bạn hoàn toàn làm chủ sourecode của mình , các bạn có thể đặt dòng lệnh (1) trong action create . Ví dụ:

Còn nếu bạn làm log_in với gem devisesourecode của gem này khá phức tạp nên sẽ làm cho bạn hơi bối rối. Bạn sẽ phải băn khoăn ngồi dò sourecode để tìm vị trí mà có thể truyền current_user vào trong dòng lệnh (1). Nhưng vì bạn đã đọc đến tận dòng này trong bài viết của mình, nên thôi thì để mình bày cho bạn một cách khá đơn giản. Đó là override lại method after_sign_in_path_for user trong sourecode của devise . Cụ thể là như này:

Cái method nói trên đơn giản là nó trả lại một đường dẫn mà Rails sẽ redirect đến sau khi đăng nhập. Nó vừa khéo lại đáp ứng đủ 2 điều kiện đặt dòng lệnh (1) của chúng ta. Thực ra cũng còn nhiều cách để đặt dòng lệnh này, ví dụ chúng ta có thể custom lại session_controllers của devise và sử dụng hàm callback after_action :current_welcome_mail, only: :create . Nhưng mà thôi, mình nghĩ cách bên trên là đơn giản nhất rồi. Đến đây là bài toán 1 đã hoàn toàn được giải quyết, và nó là nền tảng chính để chúng ta giải quyết bài toán chính ở đầu bài:

Bài toán chính: Gửi mail chúc mừng sinh nhật user dưới dạng background job?

Sau bài viết này, thì ít nhất đã hiểu cơ bản về cách hoạt động của ActionMailer rồi đúng không nào.

Techtalk via Viblo

CHIA SẺ