Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 6)

Chào các bạn, hôm nay mình sẽ tiếp tục phần 6 của Series Hướng dẫn lập trình Ruby on Rails. Ở phần trước chúng ta đã hoàn thành các chức năng sau đây:

  • Cho phép đăng ký mới một User.

  • Login với thông tin User đã đăng ký.

  • Logout sau khi Login thành công.

    Ở chức năng Login chúng ta đã có sử dụng session để lưu thông tin User cụ thể ở đây là user.id nó được viết ở đây nếu bạn nào quên :

app/helpers/sessions_helper.rb

    module SessionsHelper

      def log_in user
        session[:user_id] = user.id
      end

      def log_out
        session.delete :user_id
      end
    end 

Như vậy tạm thời sau khi chúng ta login session[:user_id] sẽ lưu id của User mà chúng ta đăng nhập, và lúc logout session[:user_id] sẽ bị delete đi

Tiếp theo chúng ta sẽ viết hàm để kiểm tra trước mỗi lần User muốn truy cập một địa chỉ nào cũng phải kiểm tra user đó đã login hay chưa, nếu đã login thì cho phép truy cập, ngược lại sẽ redirect đến Login Page để buộc phải đăng nhập trước khi muốn truy cập bất cứ trang nào.

Chúng ta sẽ viết hàm kiểm tra xem user đã đăng nhập hay chưa, hàm này sẽ dùng chung và sau này sẽ gọi lại nhiều lần nên hãy đưa nó vào SessionsHelper
Sau khi đăng nhập việc lấy thông tin user hiện tại là cần thiết, nên ta sẽ viết luôn hàm current_user để lấy thông tin user hiện tại

app/heplers/sessions_helper.rb

  # GET current_user 
  def current_user
    @current_user ||= User.find_by id: session[:user_id]
  end

  # Check user has logged in before ? 
  def logged_in?
    current_user.present?
  end

Tiếp theo chúng ta sẽ kiểm tra nếu user đã đăng nhập hay chưa, theo mặc đinh các Controller được tạo ra đều kế thừa từ ApplicationController nên ta sẽ viết hàm filter ở đây, và nó sẽ có tác dụng đối với tất cả các Controller con kế thừa từ nó.

app/controllers/application_controller.rb

  class ApplicationController < ActionController::Base
    protect_from_forgery with: :exception
    include SessionsHelper
  
    before_action :require_login

    def require_login
      unless logged_in?
        redirect_to login_path
      end
    end
  end

Trông có vẻ ok rồi đấy nhỉ, bật rails s lên vào vào thử http://localhost:3000/users xem nó có yêu cầu đăng nhập không nhé (nhớ logout trước :v)
Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 6) 3
Kết quả là không chạy được, có vẻ chúng ta đã bỏ qua một điều gì đó.
Vì chúng ta viết hàm require_login ở ApplicationController nên nó ảnh hướng đến tất cả các Controller kế thừa nó phải không nào,
trong đó có cả SessionsController < ApplicationController, do đó khi gọi redirect_to login_path sẽ gọi action #new của
SessionsController và sẽ lại chạy hàm require_login một lần nữa, cứ như vậy tạo ra vòng lặp vô hạn.
Do đó chúng ta cần phải bỏ qua hàm require_login đối với action #new, #create của SessionsController. Ta sẽ có như này

class SessionsController < ApplicationController
  skip_before_action :require_login, only: [:new, :create]
  .
  .
  . 
end

OK thử truy cập lần nữa vào http://localhost:3000/users xem nó có redirect về trang Login không nào.
Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 6) 4
Có vẻ ok rồi đấy nhỉ 😃

Ta sẽ tút tát lại cho các trang một chút nhé :

Hiển thị tất cả users hiện tại sau khi login thành công

app/controllers/users_controller.rb

class UsersController < ApplicationController

  def index
    @users = User.all
  end
  .
  .
  .
end

app/views/users/index.html.erb

<div class="container">
  <div class="row">
    <div class="col-lg-12 text-center">
      <h1 class="title">LOGIN APP</h1>
    </div>
    <div class="col-lg-12 form-group">
      <label for="">Welcome</label>
      <%= link_to current_user.name, user_path(current_user) %>
    </div>
    <div class="col-lg-12 form-group">
      <label for="">List Users</label>
      <table class="table">
        <thead>
          <th>ID</th>
          <th>User Name</th>
        </thead>
        <tbody>
          <%= render @users %>
        </tbody>
      </table>
    </div>
  </div>
</div>

app/views/users/_user.html.erb

<div class="container">
  <div class="row">
    <div class="col-lg-offset-3 col-lg-6">
      <div class="text-left col-lg-6", style="padding-left: 0px ">
        <label>User name: <%= @user.name %></label>
      </div>
      <div class="text-right col-lg-6">
        <%= link_to "Logout", logout_path, method: :delete %>
      </div>
    </div>
    <div class="col-lg-offset-3 col-lg-6">
      <%= link_to "List Users", users_path %>
    </div>
  </div>
</div>

app/views/users/show.html.erb

<div class="container">
  <div class="row">
    <div class="col-lg-offset-3 col-lg-6">
      <div class="text-left col-lg-6", style="padding-left: 0px ">
        <label>User name: <%= @user.name %></label>
      </div>
      <div class="text-right col-lg-6">
        <%= link_to "Logout", logout_path, method: :delete %>
      </div>
    </div>
    <div class="col-lg-offset-3 col-lg-6">
      <%= link_to "List Users", users_path %>
    </div>
  </div>
</div>

Các bạn có thể check lại một lượt thử logout
truy cập vào link http://localhost:3000/users nó sẽ redirect đến trang login, yêu cầu đăng nhập
sau khi login các bạn tắt tab và truy cập vào lại link trên xem, nó vào thẳng luôn và hiện tên đang nhập là mọi thứ có vẻ ok rồi đấy :v

OK, như vậy đến đây demo login_app nhỏ đã hoàn thành,

Kì tiếp theo mình sẽ giới thiệu đến các bạn các kỹ thuật khác của Rails: nested_attributes, association : has_many, has_one, belongs_to,..
validates trong Model, I18n, thiết lập file Settings,…sử dụng các loại gem thông dụng Cancancan, Devise, Kaminari, carrierwave,…
Hẹn gặp lại các bạn trong kỳ tới (bow)

Bài viết liên quan

Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 9) Hướng dẫn xây dựng ứng dụng API đơn giản với gem doorkeeper

Chào các bạn, Giới thiệu Hôm nay mình sẽ tiếp tục Series Hướng Dẫn Lập...

Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 8) – Các kỹ thuật trong Rails bạn nên biết(3)

Chào các bạn, Hôm nay mình sẽ tiếp tục Series Hướng Dẫn Lập Trình Ruby...

Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 8) – Các kỹ thuật trong Rails bạn nên biết(2)

Chào các bạn, Hôm nay mình sẽ tiếp tục Series Hướng Dẫn Lập Trình Ruby...

Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 8) – Các kỹ thuật trong Rails bạn nên biết

Chào các bạn, Dạo này công việc hơi bận rộn nên Series Hướng Dẫn Lập...

Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 7) – Deploy App On Heroku

Xin chào các bạn, Hôm nay mình sẽ tiếp tục hướng dẫn các bạn Series...

Series Hướng Dẫn Lập Trình Ruby on Rails (Phần 5)

Chào các bạn, hôm nay mình sẽ tiếp tục phần 5 của Series Hướng dẫn...

Trả lời