Khám phá Devise, Phần 2
() translation by (you can also view the original English article)
Lời giới thiệu
Trong phần đầu của chủ đề này, chúng ta đã học cách cài đặt Devise và thiết lập nó trong ứng dụng Rails của chúng ta. Trong phần này, chúng ta sẽ tìm hiểu cách tích hợp DeviseInvitable.
DeviseInvitable là một phần mở rộng hoạt động cùng với Devise. Với DeviseInvitable trong ứng dụng của bạn, người dùng của bạn có thể mời bạn bè của họ thông qua email. Đây là một tính năng tuyệt vời để thêm vào trong ứng dụng của bạn nếu bạn đang xây dựng một ứng dụng cộng tác.
Thiết lập DeviseInvitable
Mở Gemfile
của bạn và thêm gem vào:
1 |
#Gemfile |
2 |
... |
3 |
gem 'devise_invitable' |
Chạy lệnh để cài đặt bundle bundle install
.
Chạy lệnh generate để thêm tùy chọn cấu hình DeviseInvitable vào tập tin cấu hình Devise.
1 |
rails generate devise_invitable:install |
Bạn có thể thấy những thay đổi mới bằng cách kiểm tra tập tin config/initializers/devise.rb
với trình soạn thảo văn bản của bạn.
Tiếp theo, hãy thêm DeviseInvitable vào model User
của bạn.
1 |
rails generate devise_invitable User |
Điều này sẽ thêm cờ :invitable
vào model của bạn, do đó model User của bạn sẽ trông giống như cái này:
1 |
#app/models/user.rb |
2 |
|
3 |
class User < ActiveRecord::Base |
4 |
# Include default devise modules. Others available are: |
5 |
# :confirmable, :lockable, :timeoutable and :omniauthable |
6 |
devise :invitable, :database_authenticatable, :registerable, |
7 |
:recoverable, :rememberable, :trackable, :validatable |
8 |
end
|
Chạy lệnh ở trên cũng tạo ra một tập tin di trú mà trông giống như những gì tôi có dưới đây:
1 |
class DeviseInvitableAddToUsers < ActiveRecord::Migration |
2 |
def up |
3 |
change_table :users do |t| |
4 |
t.string :invitation_token |
5 |
t.datetime :invitation_created_at |
6 |
t.datetime :invitation_sent_at |
7 |
t.datetime :invitation_accepted_at |
8 |
t.integer :invitation_limit |
9 |
t.references :invited_by, polymorphic: true |
10 |
t.integer :invitations_count, default: 0 |
11 |
t.index :invitations_count |
12 |
t.index :invitation_token, unique: true # for invitable |
13 |
t.index :invited_by_id |
14 |
end
|
15 |
end
|
16 |
|
17 |
def down |
18 |
change_table :users do |t| |
19 |
t.remove_references :invited_by, polymorphic: true |
20 |
t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at |
21 |
end
|
22 |
end
|
23 |
end
|
Bây giờ di chuyển cơ sở dữ liệu của bạn bằng cách chạy rake db:migrate
.
Cấu hình Controller cho DeviseInvitable
DeviseInvitable yêu cầu được truyền một số tham số khi gửi một lời mời. Để điều này hoạt động, chúng ta cần phải tạo một danh sách trắng với các tham số cần thiết sẽ được sử dụng. Sử dụng trình soạn thảo văn bản của bạn, mở tập tin app/controllers/application_controller.rb
và làm cho nó trông giống những gì mà tôi có ở dưới:
1 |
#app/controllers/application_controller.rb |
2 |
|
3 |
class ApplicationController < ActionController::Base |
4 |
# Prevent CSRF attacks by raising an exception. |
5 |
# For APIs, you may want to use :null_session instead. |
6 |
protect_from_forgery with: :exception |
7 |
|
8 |
before_action :configure_permitted_parameters, if: :devise_controller? |
9 |
|
10 |
protected
|
11 |
|
12 |
def configure_permitted_parameters |
13 |
added_attrs = [:username, :email, :password, :password_confirmation, :remember_me] |
14 |
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs |
15 |
devise_parameter_sanitizer.permit :account_update, keys: added_attrs |
16 |
devise_parameter_sanitizer.permit :accept_invitation, keys: [:email] |
17 |
end
|
18 |
end
|
Từ ở trên, bạn có thể thấy rằng :email
đã được đưa vào danh sách trắng cho DeviseInvitable.
Bây giờ chúng ta hãy xem những gì chúng ta có thông qua giao diện dòng lệnh của chúng ta. Trên terminal của bạn, chạy rails console
và nhập những gì bạn có dưới đây.
1 |
[1] pry(main)> User.invite!(:email => "johndoe@example.com") |
Nó sẽ tạo ra những thứ trông giống như những gì tôi có dưới đây, mặc dù sẽ có thể có sự khác biệt.
1 |
[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"]] |
2 |
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."invitation_token" = ? ORDER BY "users"."id" ASC LIMIT 1 [["invitation_token", "658da470d5fcbb2275f30bc1fb66f5771b889cec2f1e56f536319d2fd1ef4a92"]] |
3 |
(0.1ms) begin transaction |
4 |
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"]] |
5 |
(220.5ms) commit transaction |
6 |
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) |
7 |
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) |
8 |
|
9 |
Devise::Mailer#invitation_instructions: processed outbound mail in 247.1ms
|
10 |
|
11 |
Sent mail to johndoe@example.com (74.3ms) |
12 |
Date: Fri, 07 Oct 2016 08:41:51 +0100 |
13 |
From: please-change-me-at-config-initializers-devise@example.com |
14 |
Reply-To: please-change-me-at-config-initializers-devise@example.com |
15 |
To: johndoe@example.com |
16 |
Message-ID: <57f751bfce8d6_18022ac6c272b12840661@kinsomicrote-X553MA.mail> |
17 |
Subject: Invitation instructions |
18 |
Mime-Version: 1.0 |
19 |
Content-Type: multipart/alternative;
|
20 |
boundary="--==_mimepart_57f751bfcc725_18022ac6c272b12840524"; |
21 |
charset=UTF-8 |
22 |
Content-Transfer-Encoding: 7bit |
23 |
|
24 |
|
25 |
----==_mimepart_57f751bfcc725_18022ac6c272b12840524 |
26 |
Content-Type: text/plain;
|
27 |
charset=UTF-8 |
28 |
Content-Transfer-Encoding: 7bit |
29 |
|
30 |
Hello johndoe@example.com |
31 |
|
32 |
Someone has invited you to https://localhost:3000/, you can accept it through the link below.
|
33 |
|
34 |
http://localhost:3000/users/invitation/accept?invitation_token=xmW9uRfyafptmeFMmFBy
|
35 |
|
36 |
|
37 |
If you don't want to accept the invitation, please ignore this email.
|
38 |
Your account won't be created until you access the link above and set your password. |
39 |
|
40 |
----==_mimepart_57f751bfcc725_18022ac6c272b12840524 |
41 |
Content-Type: text/html;
|
42 |
charset=UTF-8 |
43 |
Content-Transfer-Encoding: 7bit |
44 |
|
45 |
<p>Hello johndoe@example.com</p> |
46 |
|
47 |
<p>Someone has invited you to http://localhost:3000/, you can accept it through the link below.</p>
|
48 |
|
49 |
<p><a href="http://localhost:3000/users/invitation/accept?invitation_token=xmW9uRfyafptmeFMmFBy">Accept invitation</a></p> |
50 |
|
51 |
|
52 |
<p>If you don't want to accept the invitation, please ignore this email.<br />
|
53 |
Your account won't be created until you access the link above and set your password.</p> |
54 |
|
55 |
----==_mimepart_57f751bfcc725_18022ac6c272b12840524-- |
56 |
|
57 |
=> #<User:0x00558d875fa798 |
58 |
id: 4,
|
59 |
email: "johndoe@example.com",
|
60 |
encrypted_password: "$2a$11$0sLfqvfFDsebcmcQTUXzlOuqNIooL5z8niXeza8OUwNK3gZY/iRum", |
61 |
reset_password_token: nil, |
62 |
reset_password_sent_at: nil, |
63 |
remember_created_at: nil, |
64 |
sign_in_count: 0, |
65 |
current_sign_in_at: nil, |
66 |
last_sign_in_at: nil, |
67 |
current_sign_in_ip: nil, |
68 |
last_sign_in_ip: nil, |
69 |
created_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, |
70 |
updated_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, |
71 |
username: nil, |
72 |
invitation_token: "658da470d5fcbb2275f30bc1fb66f5771b889cec2f1e56f536319d2fd1ef4a92",
|
73 |
invitation_created_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, |
74 |
invitation_sent_at: Fri, 07 Oct 2016 07:41:51 UTC +00:00, |
75 |
invitation_accepted_at: nil, |
76 |
invitation_limit: nil, |
77 |
invited_by_id: nil, |
78 |
invited_by_type: nil, |
79 |
invitations_count: 0> |
80 |
[3] pry(main)> |
Nó hoạt động như đã định.
Bạn không muốn người dùng của bạn gửi thư mời thông qua giao diện dòng lệnh, do đó, quan trọng là chúng ta thiết lập DeviseInvitable để nó hoạt động ở front end. Thực hiện điều này là rất đơn giản; chạy lệnh generate để tạo ra các view cho DeviseInvitable.
rails generate devise_invitable:views users
Bạn cũng sẽ cần phải thêm một liên kết đến một nơi nào đó trong ứng dụng của bạn mà 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 liên kết trong tập tin navigation của bạn. Dưới đây là cách tôi đã làm:
1 |
#app/views/shared/_navigation.html.erb |
2 |
|
3 |
<nav class="navbar navbar-inverse"> |
4 |
<div class="container"> |
5 |
<div class="navbar-header"> |
6 |
<%= link_to 'Tutsplus Devise', root_path, class: 'navbar-brand' %> |
7 |
</div>
|
8 |
<div id="navbar"> |
9 |
<ul class="nav navbar-nav"> |
10 |
<li><%= link_to 'Home', root_path %></li> |
11 |
</ul>
|
12 |
<ul class="nav navbar-nav pull-right"> |
13 |
<% if user_signed_in? %> |
14 |
<li class="dropdown"> |
15 |
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> |
16 |
<%= current_user.username %> |
17 |
<span class="caret"></span> |
18 |
</a>
|
19 |
<ul class="dropdown-menu" role="menu"> |
20 |
<li><%= link_to 'Invite', new_user_invitation_path %></li> |
21 |
<li><%= link_to 'Profile', edit_user_registration_path %></li> |
22 |
<li><%= link_to 'Log out', destroy_user_session_path, method: :delete %></li> |
23 |
</ul>
|
24 |
</li>
|
25 |
<% else %> |
26 |
<li><%= link_to 'Log In', new_user_session_path %></li> |
27 |
<li><%= link_to 'Sign Up', new_user_registration_path %></li> |
28 |
<% end %> |
29 |
</ul>
|
30 |
</div>
|
31 |
</div>
|
32 |
</nav>
|
Để xem các route được tạo ra bởi DeviseInvitable, chạy lệnh rake routes | invit
. Dưới đây là những gì mà nó xuất ra.
1 |
cancel_user_registration GET /users/cancel(.:format) devise_invitable/registrations#cancel |
2 |
user_registration POST /users(.:format) devise_invitable/registrations#create |
3 |
new_user_registration GET /users/sign_up(.:format) devise_invitable/registrations#new |
4 |
edit_user_registration GET /users/edit(.:format) devise_invitable/registrations#edit |
5 |
PATCH /users(.:format) devise_invitable/registrations#update |
6 |
PUT /users(.:format) devise_invitable/registrations#update |
7 |
DELETE /users(.:format) devise_invitable/registrations#destroy |
8 |
accept_user_invitation GET /users/invitation/accept(.:format) devise/invitations#edit |
9 |
remove_user_invitation GET /users/invitation/remove(.:format) devise/invitations#destroy |
10 |
user_invitation POST /users/invitation(.:format) devise/invitations#create |
11 |
new_user_invitation GET /users/invitation/new(.:format) devise/invitations#new |
12 |
PATCH /users/invitation(.:format) devise/invitations#update |
13 |
PUT /users/invitation(.:format) devise/invitations#update |
Chúng ta hãy xem những gì chúng ta có tại thời điểm này. Chạy lệnh để khởi động server của bạn; rails server
.
Mở trình duyệt và truy cập vào http://localhost:3000/users/invitation/new
. Nhập địa chỉ email trong form, và nhấp vào nút. Nó sẽ hoạt động! Nếu bạn truy cập vào tập tin logs của máy chủ của bạn, bạn sẽ thấy một đầu ra đã được tạo khi bạn gửi lời mời. Tại đầu ra, bạn sẽ thấy một liên kết để chấp nhận lời mời.
Bạn sẽ đồng ý với tôi là nó sẽ tốt hơn nếu bạn có thể xem email được gửi trong trình duyệt của bạn. Chúng ta hãy xem làm thế nào để điều đó hoạt động được.
Tích hợp Letter_Opener
Letter Opener cho phép bạn xem trước các email trong trình duyệt mặc định của bạn. Với nó, bạn không phải thiết lập một hệ thống gởi thư khi làm việc trong môi trường phát triển.
Mở Gemfile của bạn và thêm gem dưới đây:
gem 'letter_opener'
Chạy bundle install
.
Sử dụng trình soạn thảo văn bản của bạn, điều hướng đến config/environments/development.rb
và thêm dòng code sau:
1 |
#config/environments/development.rb |
2 |
... |
3 |
config.action_mailer.delivery_method = :letter_opener |
4 |
end |
Khởi động lại rails server của bạn. Truy cập đến http://localhost:3000/users/invitation/new
. Điền và gởi form hiển thị trong đó. Lần này, một trang mới sẽ bật lên có chứa email lời mời.
Thay đổi các Route Đăng nhập và Đăng xuất mặc định
Mặc định, các route sign_in
và sign_out
khi sử dụng Devise trông giống như thế này:
sign_in
: http://localhost:3000/users/sign_in
sign_out
: http://localhost:3000/users/sign_out
Để thay đổi nó, hãy vào config/routes.rb
và thêm những thứ sau đây:
1 |
#config/routes.rb |
2 |
as :user do |
3 |
get 'signin' => 'devise/sessions#new' |
4 |
post 'signin' => 'devise/sessions#create' |
5 |
delete 'signout' => 'devise/sessions#destroy' |
6 |
end |
Bạn có thể truy cập http://localhost:3000/signin
.
Kết luận
Bây giờ bạn biết cách tận dụng DeviseInvitable. Bạn cũng đã tìm hiểu về gem letter_opener
. Có rất nhiều thứ bạn có thể làm với Devise, vì vậy hãy kiểm tra Wiki để tìm hiểu thêm. Cảm ơn bạn đã theo dõi.