Phân quyền người dùng với gem Administrate và Rolify
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ư ...
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.
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
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.