Как ограничить доступ к действию index моего ресурса, но не к отдельной записи, принадлежащей этому пользователю?

Так вот как выглядит усеченная версия моего ability.rb:

class Ability
  include CanCan::Ability

  def initialize(user)
    alias_action :create, :read, :update, :destroy, to: :crud

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

      # cannot :read, :users unless user.has_role? :admin
    end
  end
end

Мой UsersController выглядит так:

class UsersController < ApplicationController
  load_and_authorize_resource
  before_action :set_user, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:show]
  # truncated for brevity
end

Итак, то, что я пытаюсь сделать, это User#Index, я хочу ограничить это только пользователями-администраторами. Но в то же время каждый пользователь должен иметь доступ к своей пользовательской странице.

Когда я пытаюсь выполнить описанное выше, что для меня имеет смысл, я могу получить доступ к /settings для current_user, но я также могу получить доступ к Users#Index, чего я не хочу.

Вот как выглядят логи:

Started GET "/users/1547" for 127.0.0.1 at 2016-06-26 03:39:57 -0500
DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead. (called from <class:UsersController> at myapp/controllers/users_controller.rb:2)
Processing by UsersController#show as HTML
  Parameters: {"id"=>"1547"}
  User Load (2.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  User Load (1.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  Role Load (1.8ms)  SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1547]]
  CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  Rendering users/show.html.erb within layouts/application
  Rendered shared/_navbar.html.erb (2.4ms)
  Rendered shared/_footer.html.erb (1.3ms)
Completed 200 OK in 244ms (Views: 196.4ms | ActiveRecord: 16.7ms)


Started GET "/settings" for 127.0.0.1 at 2016-06-26 03:39:59 -0500
Processing by Devise::RegistrationsController#edit as HTML
  User Load (1.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  Rendering devise/registrations/edit.html.erb within layouts/application
  Rendered devise/registrations/edit.html.erb within layouts/application (16.7ms)
  Rendered shared/_navbar.html.erb (2.8ms)
  Rendered shared/_footer.html.erb (1.0ms)
Completed 200 OK in 184ms (Views: 180.4ms | ActiveRecord: 1.2ms)


Started GET "/users" for 127.0.0.1 at 2016-06-26 03:40:01 -0500
Processing by UsersController#index as HTML
  User Load (2.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  Role Load (2.2ms)  SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1547]]
  Rendering users/index.html.erb within layouts/application
  User Load (1.3ms)  SELECT "users".* FROM "users"
  Rendered users/index.html.erb within layouts/application (7.2ms)
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:40:02 -0500
Processing by UsersController#index as HTML
  User Load (2.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  Role Load (3.8ms)  SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1547]]
  Rendering users/index.html.erb within layouts/application
  User Load (51.5ms)  SELECT "users".* FROM "users"
  Rendered users/index.html.erb within layouts/application (55.1ms)
  Rendered shared/_navbar.html.erb (3.4ms)
  Rendered shared/_footer.html.erb (1.3ms)
Completed 200 OK in 533ms (Views: 488.8ms | ActiveRecord: 5.8ms)

Но когда я комментирую эту строку: can :crud, User, id: user.id, поэтому у меня есть только строка cannot :read, User, она блокирует меня от всего, как показано в приведенных ниже журналах (чего я тоже не хочу).

Started GET "/users" for 127.0.0.1 at 2016-06-26 03:45:39 -0500
Processing by UsersController#index as HTML
  User Load (1.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  Role Load (1.3ms)  SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1547]]
Redirected to http://localhost:3000/
Completed 302 Found in 19ms (ActiveRecord: 2.4ms)


Started GET "/users" for 127.0.0.1 at 2016-06-26 03:45:39 -0500
Processing by UsersController#index as HTML
  User Load (1.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1547], ["LIMIT", 1]]
  Role Load (2.8ms)  SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1547]]
Redirected to http://localhost:3000/
Completed 302 Found in 24ms (ActiveRecord: 4.0ms)

Итак, как мне добиться того, что я пытаюсь сделать?


person marcamillion    schedule 26.06.2016    source источник


Ответы (1)


Не уверен, но как насчет:

def initialize(user)
  alias_action :create, :read, :update, :destroy, to: :crud

  user ||= User.new # guest user (not logged in)
  if user.has_role?(:admin)
    can :manage, :all
  else
    cannot :read, User
    can :crud, User, id: user.id
    cannot :index, User
  # cannot :read, :users unless user.has_role? :admin
  end
end
person oreoluwa    schedule 26.06.2016
comment
Чувак. В точку. Отличное мышление! Не могу поверить, что я никогда этого не пробовал. Броски большое спасибо! - person marcamillion; 26.06.2016