Giới thiệu
Trong phần đầu tiên của hướng dẫn, chúng ta đã học cách cài đặt Devise và thiết lập cho ứng dụng Rails. Trong phần này, chúng ta sẽ xem cách tích hợp DeviseInvitable.
DeviseInvitable là một extension hoạt động cùng với Devise. Với DeviseInvitable trong ứng dụng của bạn, người dùng có thể mời bạn bè qua email. Đây là một tính năng tuyệt vời để thêm vào ứng dụng nếu bạn đang xây dựng một ứng dụng cộng tác.
Thiết lập DeviseInvitable
Mở file Gemfile và thêm gem:
# Gemfile gem 'devise_invitable'
Chạy lệnh để cài đặt: bundle install.
Chạy lệnh generator để thêm các tùy chọn cấu hình của DeviseInvitable vào file cấu hình Devise:
rails generate devise_invitable:install
Bạn có thể xem các thay đổi mới bằng cách kiểm tra config/initializers/devise.rb với trình soạn thảo văn bản.
Tiếp theo, hãy thêm DeviseInvitable vào model User của chúng ta:
rails generate devise_invitable User
Lệnh này sẽ thêm flag :invitable vào model, do đó model User sẽ trông như sau:
# app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Chạy lệnh trên cũng tạo ra một file migration trông như sau:
class DeviseInvitableAddToUsers < ActiveRecord::Migration
def up
change_table :users do |t|
t.string :invitation_token
t.datetime :invitation_created_at
t.datetime :invitation_sent_at
t.datetime :invitation_accepted_at
t.integer :invitation_limit
t.references :invited_by, polymorphic: true
t.integer :invitations_count, default: 0
t.index :invitations_count
t.index :invitation_token, unique: true
t.index :invited_by_id
end
end
def down
change_table :users do |t|
t.remove_references :invited_by, polymorphic: true
t.remove :invitations_count, :invitation_limit, :invitation_sent_at,
:invitation_accepted_at, :invitation_token, :invitation_created_at
end
end
end
Bây giờ hãy migrate database bằng lệnh rake db:migrate.
Cấu hình Controller cho DeviseInvitable
DeviseInvitable yêu cầu truyền một số tham số khi gửi lời mời. Để làm việc này, chúng cần whitelist các tham số cần thiết. Mở app/controllers/application_controller.rb và làm cho nó trông như sau:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
added_attrs = [:username, :email, :password, :password_confirmation, :remember_me]
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
devise_parameter_sanitizer.permit :accept_invitation, keys: [:email]
end
end
Từ trên, bạn có thể thấy :email đã được whitelist cho DeviseInvitable.
Bây giờ hãy xem kết quả qua console. Trên terminal, chạy rails console và nhập:
[1] pry(main)> User.invite!(email: "johndoe@example.com")
Nó sẽ tạo ra output giống như bên dưới (có thể có sự khác biệt nhỏ):
[2] pry(main)> User Load (78.3ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? ORDER BY "users"."id" ASC LIMIT 1 [["email", "johndoe@example.com"]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."invitation_token" = ? ORDER BY "users"."id" ASC LIMIT 1 [["invitation_token", "658da470d5fcbb2275f30bc1fb66f5771b889cec2f1e56f536319d2fd1ef4a92"]]
(0.1ms) begin transaction
SQL (67.8ms) INSERT INTO "users" ("email", "encrypted_password", "invitation_token", "invitation_created_at", "invitation_sent_at", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["email", "johndoe@example.com"], ["encrypted_password", "$2a$11$0sLfqvfFDsebcmcQTUXzlOuqNIooL5z8niXeza8OUwNK3gZY/iRum"], ["invitation_token", "658da470d5fcbb2275f30bc1fb66f5771b889cec2f1e56f536319d2fd1ef4a92"], ["invitation_created_at", "2016-10-07 07:41:51.254047"], ["invitation_sent_at", "2016-10-07 07:41:51.254047"], ["created_at", "2016-10-07 07:41:51.255700"], ["updated_at", "2016-10-07 07:41:51.255700"]]
(220.5ms) commit transaction
Rendered /home/kinsomicrote/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/devise_invitable-1.7.0/app/views/devise/mailer/invitation_instructions.html.erb (2.5ms)
Rendered /home/kinsomicrote/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/devise_invitable-1.7.0/app/views/devise/mailer/invitation_instructions.text.erb (88.0ms)
Devise::Mailer#invitation_instructions: processed outbound mail in 247.1ms
Sent mail to johndoe@example.com (74.3ms)
Date: Fri, 07 Oct 2016 08:41:51 +0100
From: please-change-me-at-config-initializers-devise@example.com
Reply-To: please-change-me-at-config-initializers-devise@example.com
To: johndoe@example.com
Message-ID: <57f751bfce8d6_18022ac6c272b12840661@kinsomicrote-X553MA.mail>
Subject: Invitation instructions
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary="--==_mimepart_57f751bfcc725_18022ac6c272b12840524"; charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_57f751bfcc725_18022ac6c272b12840524
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
Hello johndoe@example.com
Someone has invited you to https://localhost:3000/, you can accept it through the link below.
https://localhost:3000/users/invitation/accept?invitation_token=xmW9uRfyafptmeFMmFBy
If you don't want to accept the invitation, please ignore this email.
Your account won't be created until you access the link above and set your password.
----==_mimepart_57f751bfcc725_18022ac6c272b12840524
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit
<p>Hello johndoe@example.com</p>
<p>Someone has invited you to https://localhost:3000/, you can accept it through the link below.</p>
<p><a href="https://localhost:3000/users/invitation/accept?invitation_token=xmW9uRfyafptmeFMmFBy">Accept invitation</a></p>
<p>If you don't want to accept the invitation, please ignore this email.<br /> Your account won't be created until you access the link above and set your password.</p>
----==_mimepart_57f751bfcc725_18022ac6c272b12840524--
=> #<User:0x00558d875fa798 id: 4, email: "johndoe@example.com", encrypted_password: "$2a$11$0sLfqvfFDsebcmcQTUXzlOuqNIooL5z8niXeza8OUwNK3gZY/iRum", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, updated_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, username: nil, invitation_token: "658da470d5fcbb2275f30bc1fb66f5771b889cec2f1e56f536319d2fd1ef4a92", invitation_created_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, invitation_sent_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, invitation_accepted_at: nil, invitation_limit: nil, invited_by_id: nil, invited_by_type: nil, invitations_count: 0>
[3] pry(main)>
Điều đó hoạt động như kế hoạch.
Bạn không muốn người dùng gửi lời mời qua dòng lệnh, vì vậy việc thiết lập DeviseInvitable hoạt động trên frontend là quan trọng. Việc này rất đơn giản; chạy lệnh generator để tạo views cho DeviseInvitable:
rails generate devise_invitable:views users
Bạn cũng cần thêm một link ở đâu đó trong ứng dụng trỏ đến trang gửi lời mời (app/views/users/invitations/new.html.erb).
Đối với ứng dụng này, bạn có thể thêm link vào file navigation. Đây là cách tôi làm:
# app/views/shared/_navigation.html.erb
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<%= link_to 'Tutsplus Devise', root_path, class: 'navbar-brand' %>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><%= link_to 'Home', root_path %></li>
</ul>
<ul class="nav navbar-nav pull-right">
<% if user_signed_in? %>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<%= current_user.username %>
<span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li><%= link_to 'Invite', new_user_invitation_path %></li>
<li><%= link_to 'Profile', edit_user_registration_path %></li>
<li><%= link_to 'Log out', destroy_user_session_path, method: :delete %></li>
</ul>
</li>
<% else %>
<li><%= link_to 'Log In', new_user_session_path %></li>
<li><%= link_to 'Sign Up', new_user_registration_path %></li>
<% end %>
</ul>
</div>
</div>
</nav>
Để xem các routes do DeviseInvitable cung cấp, chạy lệnh rake routes | grep invit. Output sẽ trông như sau:
cancel_user_registration GET /users/cancel(.:format) devise_invitable/registrations#cancel user_registration POST /users(.:format) devise_invitable/registrations#create new_user_registration GET /users/sign_up(.:format) devise_invitable/registrations#new edit_user_registration GET /users/edit(.:format) devise_invitable/registrations#edit PATCH /users(.:format) devise_invitable/registrations#update PUT /users(.:format) devise_invitable/registrations#update DELETE /users(.:format) devise_invitable/registrations#destroy accept_user_invitation GET /users/invitation/accept(.:format) devise/invitations#edit remove_user_invitation GET /users/invitation/remove(.:format) devise/invitations#destroy user_invitation POST /users/invitation(.:format) devise/invitations#create new_user_invitation GET /users/invitation/new(.:format) devise/invitations#new PATCH /users/invitation(.:format) devise/invitations#update PUT /users/invitation(.:format) devise/invitations#update
Hãy xem những gì chúng ta có lúc này. Chạy lệnh để khởi động server: rails server.
Trỏ trình duyệt đến https://localhost:3000/users/invitation/new. Nhập địa chỉ email vào form hiển thị và nhấn nút. Điều đó nên hoạt động! Nếu bạn xem log của server, bạn sẽ thấy output được tạo khi bạn gửi lời mời. Trong output, bạn sẽ thấy một link để chấp nhận lời mời.
Bạn sẽ đồng ý rằng sẽ tốt hơn nếu bạn có thể xem email được gửi trong trình duyệt. Hãy xem cách làm cho điều đó hoạt động.
Tích hợp Letter_Opener
Letter Opener cho phép bạn xem trước email trong trình duyệt mặc định. Với nó, bạn không cần thiết lập hệ thống gửi mail khi làm việc trong môi trường development.
Mở Gemfile và thêm gem dưới đây:
gem 'letter_opener'
Chạy bundle install.
Mở config/environments/development.rb và thêm dòng sau:
# config/environments/development.rb config.action_mailer.delivery_method = :letter_opener end
Khởi động lại rails server. Bây giờ trỏ trình duyệt đến https://localhost:3000/users/invitation/new. Điền và submit form hiển thị. Lần này, một trang mới sẽ hiện ra chứa email mời.
Thay đổi Routes Đăng nhập/Đăng xuất Mặc định
Mặc định, các routes sign_in và sign_out khi sử dụng Devise trông như sau:
sign_in: https://localhost:3000/users/sign_in
sign_out: https://localhost:3000/users/sign_out
Để thay đổi, vào config/routes.rb và thêm:
# config/routes.rb as :user do get 'signin' => 'devise/sessions#new' post 'signin' => 'devise/sessions#create' delete 'signout' => 'devise/sessions#destroy' end
Bạn có thể trỏ trình duyệt đến https://localhost:3000/signin.
Kết luận
Bây giờ bạn đã biết cách sử dụng DeviseInvitable. Bạn cũng đã học về gem letter_opener. Có rất nhiều điều bạn có thể làm với Devise, hãy xem Wiki để tìm hiểu thêm. Cảm ơn bạn đã theo dõi.