Проблема авторизации с 3 типами ролей с использованием cancancan

#ruby-on-rails #authorization #ruby-on-rails-6 #cancancan #ruby-on-rails-6.1

Вопрос:

У меня есть таблица пользователей (созданная devise), я добавил столбец ролей, который может быть: администратор, менеджер и агент. И в user.rb я поместил ПЕРЕЧИСЛЕНИЕ вот так:

 class User < ApplicationRecord
  enum role: { admin: 0, manager: 1, agent: 2 }
end
 

Я использую канканкан и хотел бы сделать 2 вещи:

1 — Как отобразить меню или другую кнопку в соответствии с ролью зарегистрированного пользователя? На мой взгляд, я сформулировал это так:

 <% if current.present? amp;amp; current_user.admin? %>
            <%= link_to 'Purchases (Admin access)', admin_purchases_path, class: 'nav-link mr-5 ' %>
          <% end %>
 

2 — Как отобразить конкретную страницу в соответствии с ролью пользователя? В моем User.rb я поместил это:

 def admin?
    self.role == 'admin'
  end
 

Я пробую это на способности.рб:

   user ||= User.new # guest user (not logged in)
  if admin?
    can :manage, :all
  else
    can :read, :all
  end
 

И на контроллерах я поставил:

  load_and_authorize_resource
 

Но я получаю ошибку:

 NoMethodError in Home#index
undefined method `admin?' for nil:NilClass
<% if current_user.admin? %> <<< On this line here
 

Комментарии:

1. я думаю, что у вас здесь опечатка <% if current.present? amp;amp; current_user.admin? %>

Ответ №1:

Вы можете использовать оператор безопасной навигации, чтобы избежать нулевой ошибки:

 <% if current_useramp;.admin? %>
 

Однако это все еще несколько противоречит образцу. Весь смысл использования библиотеки авторизации, такой как CanCanCan, состоит в том, чтобы консолидировать логику авторизации, а не распространять ее на все ваши контроллеры и представления.

Вместо этого вам следует спросить CanCanCan, имеет ли пользователь право делать то, что делает ссылка:

 <% if can? :administrate, :purchases %>
  <%= link_to 'Purchases (Admin access)', admin_purchases_path, class: 'nav-link mr-5 ' %>
<% end %>
 

Ему не обязательно знать, является ли пользователь администратором или что администраторам разрешено администрировать покупки. Это работа канканцев.

 user ||= User.new # guest user (not logged in)
if user.admin?
  can :manage, :all
  can :administrate, :all
else
  can :read, :all
end
 

В моем User.rb я поместил это ..

Этот код полностью повторяется. enum role: { admin: 0, manager: 1, agent: 2 } уже создает методы admin? взаимодействия , manager? и agent? .

Проблема в ability.rb том, что вы звоните if admin? , фактически не указывая получателя. Ты должен был позвонить if user.admin? .