Рефакторинг драгоценного камня Rails CanCan Класс Ability

У меня есть около 13 моделей в моем приложении rails, я использую возможности для всех из них. Мой класс способностей стал огромным. У меня разные условия способностей для разных действий CRUD, что затрудняет управление.

Может ли кто-нибудь подсказать мне, как я могу реорганизовать это..? Например, использовать модули или классы, чтобы мой класс способностей выглядел аккуратно.


person aBadAssCowboy    schedule 20.03.2014    source источник


Ответы (3)


Простой сценарий: если вы можете разделить разрешения на несколько взаимоисключающих наборов, тогда вам следует проверить это предложение от @ryanb, создателя CanCan, в котором он разделяет способности на несколько разных классов, а затем перезаписывает current_ability метод в ApplicationController

Как разбить большой класс способностей в CanCan — Gists

Более сложный сценарий: если у вас есть несколько разных перекрывающихся наборов разрешений, вы можете попробовать следующий подход:

# app/models/ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    self.merge Abilities::Everyone.new(user)

    if user
      self.merge Abilities::Admin.new(user) if user.admin?
      self.merge Abilities::Authenticated.new(user)
    else
      self.merge Abilities::Guest.new(user)
    end
  end
end

# app/models/abilities/admin.rb
module Abilities
  class Admin
    include CanCan::Ability

    def initialize(user)
      # define abilities here ...
    end
  end
end

# app/models/abilities/everyone.rb
...

И так далее для остальных файлов.

person dgilperez    schedule 06.08.2014

Часть решения, упомянутого здесь, действительно привлекательна. Я хотел бы предложить альтернативный метод для обработки этого, где мы переопределяем метод current_ability в application_controller, чтобы сделать его динамическим в зависимости от используемого контроллера. Оттуда мы можем указать возможность использования в каждом контроллере. Это может выглядеть примерно так:

./app/abilities
              ./posts_ability.rb
              ./comments_ability.rb
              ./admin_ability.rb
              ./pictures_ability.rb
              ./uploads_ability.rb

Тогда в ./app/controllers/my_controller.rb это будет выглядеть так:

class MyController < ApplicationController
    authorize_with PostsAbility
end

Это также может быть автоматическим, когда PostsController будет использовать PostsAbility по умолчанию.

Однако, оглядываясь назад, есть одна вещь, которую следует учитывать. Кажется, есть два способа масштабировать способности. С одной стороны, у нас может быть много «ролей», которым разрешено по-разному взаимодействовать с данными. Другой способ заключается в том, что у нас есть много моделей, и нам нужен способ разделить логику там. Этот подход хорошо работает с обоими из них, потому что вы можете разделить логику на основе действия, которое выполняется (или может быть выполнено).

Еще одна вещь: мы также можем использовать наследование для предварительной загрузки взаимозависимых способностей. Если Comment принадлежит Post, то CommentsAbility может наследоваться от PostsAbility, чтобы добавить необходимую логику.

person William Hatt    schedule 13.12.2015

Вы можете просто переместить свой класс способностей в базу данных и управлять всеми разрешениями там и извлекать, прежде чем проверять способность current_user выполнять действие. Перенос разрешений в базу данных не займет много времени.

person Ravi D    schedule 20.03.2014