Phân quyền người dùng với gem Administrate và Rolify
Bài đăng này đã không được cập nhật trong 8 năm
Administrate là một thư viện Rails tự động tạo ra trang quản lý admin. Trang quản lý này sẽ tạo ra giao diện mặc định cho phép người dùng có thể thêm, sửa hoặc xóa các bạn ghi của tất cả các model trong ứng dụng.
Hệ thống nào cũng cần phải có chức năng phân quyền, ở đây tôi giới thiệu một thư viện hỗ trợ phân quyền khá hay đó là gem Rolify. Và chúng ta sẽ có một giao diện quản lý phân quyền cho tất cả người dùng một cách rất nhanh và linh hoạt.
Cài đặt Rolify
Thêm vào trong Gemfile
gem 'rolify' 
Sau đó bundle install
chạy lệnh sau để kích hoạt:
$ rails g rolify Role User
và migrate
$ rake db:migrate
Một model role sẽ được tạo ra hỗ trợ admin phân quyền Chúng ta tạo những quyền truy cập khác nhau để lưu vào database
Role.create name: :normal
Role.create name: :staff
Role.create name: :admin
Cài đặt Administrate
Thêm vào trong Gemfile
gem 'administrate' 
tiếp theo
$ bundle install
chạy lệnh sau để cài đặt vào hệ thống
$ rails generate administrate:install
Cài đặt giao diện quản lý phân quyền:
$ rails generate administrate:dashboard Role
Bạn nên cài đặt routes cho Users và Roles ví dụ như sau:
# config/routes.rb
namespace :admin do
  resources :users
  resources :roles, only: [:index, :show]
  root to: "users#index"
end
Chỉ cho phép người dùng có quyền admin mới được thực hiện:
# app/controllers/admin/application_controller.rb
module Admin
  class ApplicationController < Administrate::ApplicationController
    before_action :authenticate_user!
    before_action :authenticate_admin
    def authenticate_admin
      redirect_to root_path, alert: 'Not authorized.' unless current_user.has_role?(:admin)
    end
  end
end
Bây giờ chúng ta sẽ cấu hình giao diện phân quyền để chỉ nhìn thấy tên quyền:
# app/dashboards/role_dashboard.rb
class RoleDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    name: Field::String,
  }.freeze
  COLLECTION_ATTRIBUTES = [
    :name,
  ].freeze
  SHOW_PAGE_ATTRIBUTES = [
    :name,
  ].freeze
  FORM_ATTRIBUTES = [
    :name,
  ].freeze
end
Để chỉnh sửa giao diện quản lý phân quyền, chúng ta cần tạo một CustomField kế thừa HasManyField
$ rails generate administrate:field HasManyRoles
Những file bên dưới phải được sửa như sau:
# fields/has_many_roles_field.rb 
# https://github.com/thoughtbot/administrate/issues/192
require "administrate/field/base"
class HasManyRolesField < Administrate::Field::HasMany
end
# app/views/fields/has_many_roles_field/_form.html.erb
<div class="field-unit__label">
  <%= f.label field.attribute_key, field.attribute %>
</div>
<div class="field-unit__field">
  <%= f.select(field.attribute_key, nil, {}, multiple: true) do %>
  <%= options_for_select(field.associated_resource_options, field.selected_options) %>
  <% end %>
</div>
# app/views/fields/has_many_roles_field/_index.html.erb
<%= field.data.pluck(:name).join(' ') %>
# app/views/fields/has_many_roles_field/_show.html.erb
<%= field.data.pluck(:name).join(' ') %>
Bây giờ chúng ta tiến hành sửa để hiển thị quyền truy cập
# app/dashboards/user_dashboard.rb
class UserDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    id: Field::Number,
    email: Field::String,
    roles: HasManyRolesField,
  }.freeze
  COLLECTION_ATTRIBUTES = [
    :roles,
    :id,
    :email,
  ].freeze
  SHOW_PAGE_ATTRIBUTES = [
    :roles,
    :id,
    :email,
  ].freeze
  FORM_ATTRIBUTES = [
    :roles,
    :email,
  ].freeze
end
Restart server và vào đường dẫn http://localhost:3000/admin/users để xem giao diện quản lý mới
Bonus: Phân quyền mặc định cho người dùng mới
# app/models/user.rb
class User < ApplicationRecord
  ...
  after_initialize :set_default_role, if: :new_record?
  validates :roles, presence: true
  def set_default_role
    self.add_role(:normal)
  end
end
Extra bonus: validate quyền truy cập:
# app/models/role.rb
class Role < ApplicationRecord
...
validates :name,
        inclusion: { in: ["admin", "normal", "staff"] },
        uniqueness: true
end
Sử dụng Administrate, chúng ta có thể dễ dàng thực hiện được phân quyền một cách linh hoạt chỉ bởi một số dòng code đơn giản.
All rights reserved
 
  
 