RoR: разные роли пользователей для каждой новой созданной записи?

Я хочу сделать систему управления записями. В системе будет 4 разных роли пользователя: Admin, Viewer, Editor и Reviewer.

В то время как первые два легко реализовать с помощью таких жемчужин, как cancan и декларативная авторизация, два других не так просты.

В основном каждая новая запись создается Admin (только администратор может создавать новые записи) и должна иметь свои отдельные роли Editor и Reviewer. То есть пользователю может быть назначено много разных ролей в разных записях, но не в других, поэтому пользователю может быть назначено Editor ролей для записи A и C, но не B и т. д.

  • Редактор: может вносить изменения в запись и будет иметь доступ к определенным методам в контроллере, таким как редактирование и т. д.

  • Рецензент: сможет просмотреть (просмотреть изменения), внесенные в запись, и либо одобрить ее, либо отправить комментарии и отклонить.

  • Средство просмотра: может просматривать только самую последнюю утвержденную версию каждой записи.

Существуют ли какие-либо способы обработки таких ролей пользователей, зависящих от записи?


person Mo.    schedule 13.02.2011    source источник


Ответы (1)


Этого можно добиться без особых усилий с помощью драгоценного камня канкан и условия блока. Условие блокировки проверяет авторизацию для экземпляра. Предполагая, что в вашем классе Record есть метод editors, который возвращает массив авторизованных редакторов, возможность канкана для обновления записи может выглядеть примерно так:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)

    ...

    can :update, Record do |record|
      record.editors.include?(user)
    end

    ...    

  end
end

См. «Условия блокировки» на вики CanCan: https://github.com/ryanb/cancan/wiki/Defining-Abilities

Обновить

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

class UserRecordRoles < ActiveRecord::Base
  # Has three fields:  role, user_id, record_id
  attr_accessible :role, :user_id, :record_id
  belongs_to :user_id
  belongs_to :record_id
end

Теперь создайте ассоциацию has_many в моделях User и Record, чтобы можно было легко запрашивать все назначения ролей. Метод редактора может выглядеть так:

class Record < ActiveRecord::Base

  ...

  has_many :user_record_roles

  def editors
    # This is rather messy and requires lot's of DB calls...
    user_record_roles.where(:role => 'editor').collect {|a| a.user}
    # This would be a single DB call but I'm not sure this would work.  Maybe someone else can chime in?  Would look cleaner with a scope probably.
    User.joins(:user_record_roles).where('user_record_roles.role = ?' => 'editor')
  end

  ...

end

Конечно, есть много способов сделать это, и они сильно различаются в зависимости от ваших потребностей. Идея состоит в том, что CanCan может общаться с вашей моделью при определении авторизации, что означает, что может быть представлена ​​любая логика, которую вы можете придумать. Надеюсь это поможет!

person MDaubs    schedule 13.02.2011
comment
Спасибо за ответ, всего пара вопросов, как бы вы создали новые роли для записи при ее создании и как затем назначить их роли пользователю? я спрашиваю, как будет работать метод редакторов? - person Mo.; 13.02.2011
comment
@Mo, это стало немного сложнее, но я надеюсь, что это достаточно ясно. На самом деле хранение ролей очень специфично для приложения. Что бы ни имело смысл для вашего проекта, это путь. Как только вы выясните, что имеет наибольшее значение для вашего приложения, расскажите CanCan, как работает ваше приложение, и разбросайте эти can? методы по вашему приложению. Мне было бы очень интересно, если бы кто-нибудь улучшил мой метод editors! Мне плохо пахнет. - person MDaubs; 13.02.2011
comment
@MDabus Я думал о создании таблицы ролей, которая будет иметь отношение «многие ко многим» с пользователями. затем, когда создается новая запись, система может создать 2 новые роли в таблице ролей (созданные объекты ролей получат идентификатор записи). затем на странице редактирования пользователя пользователям могут быть назначены роли. метод editors может перебирать всех пользователей, принадлежащих к этой роли записей, и добавлять их в массив? это все теоретически, как вы думаете, это сработает? - person Mo.; 13.02.2011
comment
@Mo Это звучит выполнимо в теории. Если назначение роли связано с ролью, пользователем и записью, я бы удостоверился, что эти отношения отражены в ваших моделях с помощью ассоциаций has_many, has_many :through и own_to. Тогда вы бы использовали область редактора вместо того, чтобы писать метод редактора вручную. На самом деле нет никаких причин вручную перебирать пользователей для создания собственного массива, если ваши ассоциации точно отражают реальную бизнес-модель. - person MDaubs; 14.02.2011