CanCan и наборы данных - PullRequest
       1

CanCan и наборы данных

4 голосов
/ 13 декабря 2010

Я некоторое время боролся с этим и наконец дошел до того, что кажется, что CanCan не позволяет вам авторизовать коллекцию записей.Например:

ads_controller.rb

def index
    @ads = Ad.where("ads.published_at >= ?", 30.days.ago).order("ads.published_at DESC")
    authorize! :read, @ads
end

able.rb

def initialize(user)
  user ||= User.new # Guest user

  if user
    if user.role? :admin  # Logged in as admin
      can :manage, :all
    else                  # Logged in as general user
      can :read, Ad
      can :read_own, Ad, :user_id => user.id
      can :create, Ad
    end
  else                    # Not logged in (Guest)
    can :read, Ad
  end
end

В результате появляется сообщение о несанкционированном доступе при попытке получить доступ к действию индекса.

You are not authorized to access this page.

Однако, если вы измените вызов авторизации в действии index, чтобы проверить класс Ad, а не коллекцию, как это

def index
    @ads = Ad.where("ads.published_at >= ?", 30.days.ago)
    authorize! :read, Ad
end

... он работает нормально.

Любая помощь в объяснении этого будет принята с благодарностью.

Заранее спасибо.

пс.Первоначально я получал петли перенаправления при попытке решить это.Оказывается, есть одна ошибка с рекомендуемым значением rescue_from, которую вы помещаете в контроллер приложения, чтобы получить хорошие сообщения об ошибках.Если ваш root_path установлен в то же место, где вы авторизуетесь!Вызов не является истинным (или неудачным), вы получите цикл перенаправления.Закомментируйте rescue_from Узнал, что это трудный путь.

Ответы [ 2 ]

2 голосов
/ 03 мая 2012

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

# time_off_requests_controller.rb
authorize! :read, *@time_off_requests

# Ability.rb
can :manage, TimeOffRequest do |*time_off_requests|
  membership.has_any_role?(:admin, :manager) ||
    time_off_requests.all? { |tor| membership.id == tor.employee_id }
end

Я подробно писал об этом здесь, если вам интересно: http://zacstewart.com/2012/01/08/defining-abilities-for-collections-of-records-using-cancan.html

2 голосов
/ 13 декабря 2010

CanCan не предназначен для такого использования.Вы можете проверить, есть ли у пользователя права доступа к классу модели (например, Ad) или к одному экземпляру (например, @ad).

Я предлагаю вам использовать accessible_by для фильтрации вашей коллекции:

@ads = Ad.where("ads.published_at >= ?", 30.days.ago).accessible_by(current_ability) 
# @ads will be empty if none are accessible by current user

raise CanCan::AccessDenied if @ads.empty?  # handle however you like

Другой подход заключается в определении настраиваемого разрешения на основе условий, которые вы используете для извлечения коллекции:

# ability.rb
can :read_ads_from_past_month, Ad, ["ads.published_at >= ?", 30.days.ago]

# in your controller
def index
  authorize! :read_ads_from_past_month, Ad
  @ads = Ad.where("ads.published_at >= ?", 30.days.ago)
end
...