Thêm tính năng xác thực người dùng (authentication) với Devise

Viết bởi Piotr Steininger, @polishprince Cập nhật bởi Ernesto Jimenez, @ernesto_jimenez

Hướng dẫn này giả định rằng bạn đã xây dựng một ứng dụng Rails Girl bằng cách làm theo hướng dẫn phát triển ứng dụng

1. Thêm devise gem

Mở Gemfile của bạn và thêm vào dòng sau

gem 'devise'

Và chạy lệnh sau

bundle install

để cài đặt devise gem.

Và nhớ bạn cần phải khởi động lại server

2. Thiết lập devise cho ứng dụng của bạn

Chạy lệnh sau trên terminal

rails g devise:install

3. Cấu hình Devise

Hãy chắc chắn rằng bạn đã định nghĩa một default_url_options trong các tập tin môi trường của bạn. Mở tập tin config/environments/development.rb và thêm vào dòng sau

 config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

trước từ khóa end ở cuối tập tin đó.

Mở tập tin app/views/layouts/application.html.erb và thêm vào

<% if notice %>
  <p class="alert alert-success"><%= notice %></p>
<% end %>
<% if alert %>
  <p class="alert alert-danger"><%= alert %></p>
<% end %>

ngay phía trên

 <%= yield %>

Mở tập tin app/views/ideas/show.html.erb và xóa dòng có nội dung như sau

<p id="notice"><%= notice %></p>

Thực hiện tương tự với tập tin app/views/comments/show.html.erb. Những dòng thông báo này là không cần thiết vì chúng ta đã đưa chúng vào tập tin app/views/layouts/application.html.erb

4. Thiết lập User model

Chúng ta sẽ sử dụng một generator script để khởi tạo User model

 rails g devise user
 rails db:migrate

Và nhớ bạn cần phải khởi động lại server

Coach: Giải thích về user model đã được tạo ra. Các trường (fields) nào được tạo ra và nó là gì?

5. Tạo user đầu tiên

Bây giờ, khi mà bạn đã thiết lập xong tất cả mọi thứ bạn có thể tạo user đầu tiên. Devise đã tạo ra tất cả các đoạn code cũng như routes cần thiết để bạn có thể tạo mới accounts, đăng nhập hay đăng xuất v.v.

Hãy chắc chắn rằng rails server của bạn vẫn đang chạy. Mở http://localhost:3000/users/sign_up (lưu ý đây là địa chỉ server của bạn. Hiện tại hướng dẫn này sử dụng c9.io nên đường dẫn sẽ khác) và tạo tài khoản cho bạn.

6. Thêm vào liên kết đăng kí và đăng nhập

Tất cả những điều chúng ta cần làm bây giờ là thêm liên kết (links) hoặc là thông báo (notice) thích hợp thông báo về tình trạng đăng nhập của người dùng đặt ở góc bên phải của thanh navigation.

Để làm được điều đó, mở tập tin app/views/layouts/application.html.erb và thêm vào

<p class="navbar-text pull-right">
<% if user_signed_in? %>
  Logged in as <strong><%= current_user.email %></strong>.
  <%= link_to "Edit profile", edit_user_registration_path, :class => 'navbar-link' %> |
  <%= link_to "Logout", destroy_user_session_path, method: :delete, :class => 'navbar-link'  %>
<% else %>
  <%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link'  %> |
  <%= link_to "Login", new_user_session_path, :class => 'navbar-link'  %>
<% end %>

vào ngay dưới những dòng sau

<ul class="nav">
  <li class="active"><a href="/ideas">Ideas</a></li>
</ul>

Cuối cùng, chúng ta sẽ buộc người dùng chuyển hướng đến trang đăng nhập nếu người dùng chưa đăng nhập vào ứng dụng. Mở tập tin app/controllers/application_controller.rb và thêm vào dòng sau

before_action :authenticate_user!

ngay sau dòng

protect_from_forgery with: :exception

Mở trình duyệt của bạn và hãy thử đăng nhập, đăng xuất.

Coach: Nói về các helpersuser_signed_in?current_user. Tại sao chúng lại hữu ích?

Tiếp theo là gì?

Những câu hỏi nâng cao

A Dễ

Trong cửa sổ dòng lệnh bạn gõ lệnh sau
rails generate migration AddUserNameToUsers user_name:string telephone:string
rails db:migrate

Mở tệp tin config/environments/development.rb và thêm vào đonaj code sau trước từ khóa end ở cuối tệp tin:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address:              'smtp.gmail.com',
port:                 587,
user_name:            '<gmail username>',
password:             '<gmail password>',
authentication:       'plain',
enable_starttls_auto: true  }

B Bình thường

rails generate scaffold_controller Users
Mở tệp tin config/routes.rb và thêm vào
resource :user, only: [:edit, :update]
Thay toàn bộ nội dung fileapp/controllers/users_controller.rb với nội dung như sau
class UsersController < ApplicationController
  def edit
    @user = current_user
  end

  def update
    @user = current_user
    if @user.update(user_params)
      redirect_to root_path, notice: 'Profile was successfully updated.'
    else
      render :edit
    end
  end

  private
  def user_params
    params.require(:user).permit(:user_name, :telephone)
  end
end
Thay toàn bộ nội dung file app/views/users/edit.html.erb với nội dung sau
<h1>Editing Profile</h1>
<%= form_for @user do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this idea from being saved:</h2>

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

  <div class="field">
    <%= f.label :user_name %><br>
    <%= f.text_field :user_name %>
  </div>
  <div class="field">
    <%= f.label :telephone %><br>
    <%= f.text_field :telephone %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
Mở tệp tin app/views/layouts/application.html.erb và thay đổi các dòng
Logged in as <strong><%= current_user.email %></strong>.
<%= link_to 'Edit profile', edit_user_registration_path, :class => 'navbar-link' %> |
thành những dòng sau:
Logged in as <strong><%= current_user.user_name || current_user.email %></strong>.
<%= link_to 'Edit Password', edit_user_registration_path, :class => 'navbar-link' %> |
<%= link_to 'Edit Profile', edit_user_path, :class => 'navbar-link' %> |
Bây giờ hãy thử khởi động lại server và duyệt tới trang http://localhost:3000/user/edit xem sao?

Trước hết cần thêm vào trường user_id cho bảng ideas
rails generate migration AddUserIdToIdeas user_id:integer
rails db:migrate
Mở tệp tin app/models/user.rb và thêm vào dòng sau
has_many :ideas
Tiếp đó mở tệp tin app/models/idea.rb và thêm vào dòng sau
belongs_to :user
Trong tệp tin app/views/ideas/_form.html.erb bạn thêm vào dòng sau
<%= form.hidden_field :user_id, value: current_user.id %>
Cuối cùng cần cấp quyền truy cập user_id cho ideas_params. Trong tệp tin app/controllers/ideas_controller.rb tìm hàm ideas_params và thay thế dòng code trong hàm bằng dòng dưới đây
params.require(:idea).permit(:name, :description, :picture, :user_id)

Trước hết cần thêm vào trường user_id cho bảng comments
rails generate migration AddUserIdToComments user_id:integer
rails db:migrate
Mở tệp tin app/models/user.rb và thêm vào dòng sau
has_many :comments
Tiếp đó mở tệp tin app/models/comment.rb và thêm vào dòng sau
belongs_to :user
Trong tệp tin app/views/comments/_form.html.erb bạn thêm vào dòng sau
<%= form.hidden_field :user_id, value: current_user.id %>
Cuối cùng cần cấp quyền truy cập user_id cho comments_params. Trong tệp tin app/controllers/comments_controller.rb tìm hàm comments_params và thay thế dòng code trong hàm bằng dòng dưới đây
params.require(:comment).permit(:user_name, :body, :idea_id, :picture, :reply_id, :user_id)
**Lưu ý**: trường :picturereply_id ở trên là những phần mở rộng cho các câu hỏi trong phần 5, nếu bạn nào bỏ qua phần đó thì ta có thể bỏ 2 trường đó đi.

C Khó