CanCan: ограничение возможности пользователя устанавливать определенные атрибуты модели на основе их роли
У меня есть модель Post с атрибутом :published
(boolean) и Пользователь с атрибутом role
(строка). Существует три роли: ROLES = %w[admin publisher author]
Я не хочу, чтобы пользователи, чья роль автор, могли устанавливать или редактировать поле :published
в модели Post.
Я использую CanCan (и RailsAdmin gem), и мой упрощенный файл Ability.rb выглядит так:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.role? :admin
can :manage, :all
elsif user.role? :publisher
can :manage, Post
elsif user.role? :author
# I want to prevent these guys from setting the :published attribute
end
end
end
У кого-нибудь есть какие-то советы для такого рода вещей?
Ответы
Ответ 1
Пока это невозможно. Но в соответствии с этим: https://github.com/ryanb/cancan/issues/326 эта функция должна быть в cancan 2.0.
Обновление: вы можете увидеть это на ветке CanCan 2.0 здесь: https://github.com/ryanb/cancan/tree/2.0 в разделе "Атрибуты ресурсов"
Ответ 2
Отправлено: Как использовать CanCan с rails admin для проверки прав собственности
Показывает, как сделать поле невидимым на основе роли пользователя.
UPDATE
Мне удалось установить параметры в rails admin с помощью этого кода:
config.model User do
edit do
configure :organization do
visible do
bindings[:view]._current_user.max_role_name != 'admin' ? false : true
end
end
configure :organization_id, :hidden do
visible do
true if bindings[:view]._current_user.max_role_name != 'admin'
end
default_value do
bindings[:view]._current_user.organization_id if bindings[:view]._current_user.max_role_name != 'admin'
end
end
include_all_fields
end
end
Эта конфигурация скроет поле организации, если зарегистрированный пользователь не является администратором. Затем он отобразит поле organization_id (установлено в type = 'hidden) и установит значение по умолчанию.
Надеюсь, это поможет кому-то.
Ответ 3
Пока CanCan 2.0 не появится, я решил это, создав подкласс модели с ограниченной доступностью, например:
class AuthorPost < Post
attr_protected :published
end
И затем дайте авторам доступ к AuthorPosts: can :manage => AuthorPost
Затем в вашем контроллере вы можете установить нужный ресурс в файле before_filter:
before_filter :set_resource
...
private
def set_resource
if current_user and current_user.author?
@resource = AuthorPost
else
@resource = Post
end
params[:post] ||= params[:author_post]
end
Последнее предостережение: вы не сможете использовать load_and_authorize_resource
в этом контроллере. Вам нужно будет сделать это вручную, как описано здесь: https://github.com/ryanb/cancan/wiki/Controller-Authorization-Example
Вам нужно заменить Project
на @resource
.
Я нахожусь на заборе относительно того, является ли это более или менее эффективным, чем метод, описанный в railscast. В моих целях он оставил оригинальную модель полностью неповрежденной, поэтому мой другой код не был затронут - и просто позволил мне предоставить некоторым пользователям меньше редактируемых полей.
Ответ 4
Есть способ, я сделал что-то подобное в моем проекте. Но CanCan - это не совсем ответ. Что вам нужно сделать, так это сделать attr_accessible в динамике модели на основе роли пользователя, поэтому, если вы являетесь администратором, вам разрешено обновлять опубликованное поле. Если нет, то при задании поля новое значение просто не будет выполняться при сохранении модели.
Railscasts снова приходит на помощь: http://railscasts.com/episodes/237-dynamic-attr-accessible
После получения внутренней части реализованной функции вы можете сделать что-то в форме frontend, обернув поле публикации в представлении с проверкой ролей или чем-то, чтобы показать или скрыть поле на основе пользователя. Грубый пример моей реализации...
<% if current_user.roles.where(:name => ['Administrator','Editor']).present? %>
<%= f.label :display_name %>
<%= f.text_field :display_name %>
<% end %>