Контекст
В моем приложении user.admin может создать несколько отелей.
Для каждого из этих отдельных отелей user.admin может пригласить одного (или более) user.employee или другого user.admin.
Таким образом, между пользователями и отелями существует множество отношений.
Issue
- Когда приглашенный пользователь - user.admin, все работает как шарм. Приглашенный user.admin может получить доступ
hotels#show
. - Однако, когда приглашенный пользователь является пользователем user.employee, он / она не может получить доступ к
hotels#show
- Назначение ролей, кажется, работает
current_user.employee? => true
- Отели / шоу. html.erb содержит только
<p>show_page</p>
сообщение об ошибке
сообщение в веб-браузере:
localhost redirected you too many times.
Try clearing your cookies.
ERR_TOO_MANY_REDIRECTS
консоль
Started GET "/" for ::1 at 2019-11-07 09:27:16 +0100
Processing by PagesController#home as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 20], ["LIMIT", 1]]
↳ app/controllers/pages_controller.rb:6
Hotel Exists (0.5ms) SELECT 1 AS one FROM "hotels" INNER JOIN "user_hotels" ON "hotels"."id" = "user_hotels"."hotel_id" WHERE "user_hotels"."user_id" = $1 LIMIT $2 [["user_id", 20], ["LIMIT", 1]]
↳ app/controllers/pages_controller.rb:7
Hotel Load (0.2ms) SELECT "hotels".* FROM "hotels" WHERE "hotels"."id" IS NULL LIMIT $1 [["LIMIT", 1]]
↳ app/controllers/pages_controller.rb:8
Hotel Load (0.2ms) SELECT "hotels".* FROM "hotels" INNER JOIN "user_hotels" ON "hotels"."id" = "user_hotels"."hotel_id" WHERE "user_hotels"."user_id" = $1 ORDER BY "hotels"."id" DESC LIMIT $2 [["user_id", 20], ["LIMIT", 1]]
↳ app/controllers/pages_controller.rb:12
Redirected to http://localhost:3000/hotels/9
Completed 302 Found in 6ms (ActiveRecord: 1.2ms)
код
маршруты
Rails.application.routes.draw do
devise_for :users
resources :hotels do
devise_for :users, :controllers => { :invitations => 'users/invitations' }
end
end
application_controller
class ApplicationController < ActionController::Base
before_action :set_locale
before_action :configure_permitted_parameters, if: :devise_controller?
def set_locale
I18n.locale = params.fetch(:locale, I18n.default_locale).to_sym
end
def default_url_options
{ locale: I18n.locale == I18n.default_locale ? nil : I18n.locale }
end
protect_from_forgery with: :exception
before_action :authenticate_user!
include Pundit
# Pundit: white-list approach.
after_action :verify_authorized, except: :index, unless: :skip_pundit?
after_action :verify_policy_scoped, only: :index, unless: :skip_pundit?
# Uncomment when you *really understand* Pundit!
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private
def user_not_authorized
flash[:alert] = "You are not authorized to perform this action."
redirect_to(root_path)
end
def skip_pundit?
devise_controller? || params[:controller] =~ /(^(rails_)?admin)|(^pages$)/
end
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:invite, keys: [:role, :user_parks_attributes])
end
end
страницы # home
class PagesController < ApplicationController
skip_before_action :authenticate_user!, :raise => false
skip_after_action :verify_authorized
def home
if !current_user.nil?
if current_user.hotels.any?
if Hotel.find_by_id params[:id]
@hotel = Hotel.find(params[:id])
redirect_to hotel_path(@hotel)
else
@hotel = current_user.hotels.last
redirect_to hotel_path(@hotel)
# redirect_to :controller => 'hotels' , :action => 'show', :id => @hotel.id
end
else
redirect_to hotels_path
end
else
redirect_to pages_landing_page_path
end
end
end
hotel_policy
class HotelPolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user.admin? || user.employee?
scope.joins(hotel: :user_hotels).where(user_hotels: { user_id: user.id })
else
raise Pundit::NotAuthorizedError
end
end
end
def show?
user.admin? || user.employee?
end
end
модели
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
has_many :user_hotels, dependent: :destroy
has_many :hotels, through: :user_hotels
accepts_nested_attributes_for :user_hotels
enum role: [:owner, :admin, :employee]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :admin
end
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :invitable
end
class UserHotel < ApplicationRecord
belongs_to :hotel
belongs_to :user
end
class Hotel < ApplicationRecord
has_many :user_hotels, dependent: :destroy
has_many :users, through: :user_hotels
accepts_nested_attributes_for :users, allow_destroy: true, reject_if: ->(attrs) { attrs['email'].blank? || attrs['role'].blank?}
end
hotels_controller
class HotelsController < ApplicationController
def show
if Hotel.find_by_id params[:id]
@hotel = Hotel.find(params[:id])
else
@hotel = current_user.hotels.last
end
authorize @hotel
@reservations = @hotel.reservations
end
end