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) 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. 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)


All Rights Reserved