Мне нужно получать только определенные записи из базы данных при определенных условиях, используя CanCanCan. Это моя модель данных.
class User < ApplicationRecord
has_many :regions_users
end
class RegionsUser < ApplicationRecord
belongs_to :region
end
class Region < ApplicationRecord
has_many :regions_users
has_many :sites
end
class Site < ApplicationRecord
belongs_to :region
has_many :offers
end
class Offer < ApplicationRecord
belongs_to :site
end
Например, пользователю назначены два региона, что означает, что пользователь
user.regions_users
возвращает и массив из двух RegionsUser [RegionsUser1, RegionsUser2]. RegionsUser1 принадлежит к области A, а RegionsUser2 принадлежит к области B, поэтому, если я вошел в систему как пользователь, я являюсь пользователем региона, который может контролировать данные, принадлежащие этим регионам. Теперь мне нужно отобразить предложения, которые принадлежат этим регионам (регион A и регион B). Это означает, что пользователь не может получить доступ к предложению, относящемуся к региону, отличному от региона A и региона B, поэтому при доступе к /offers/3
должно появиться сообщение Access Denied
error.
Я могу вытащить регионы из RegionsUser:
region_ids = user.regions_users.pluck(:regions_id)
, а затем предложения:
Offer.joins(:site).where(sites: { region_id: region_ids })
Я читал об определении способностей, используя описанный блок здесь
can :update, Project, ["priority < ?", 3] do |project|
project.priority < 3
end
но я не могу придумать никакого решения для моего случая. Буду признателен за любые идеи.
UPDATE
Это вроде работает, но вместо отображения страницы «Отказано в доступе» возникает ошибка 404 Page Not Found.
offers_controller.rb
def offer
@offer ||= Offer.accessible_by(current_ability).find(params[:id])
end
ability.rb
if user.region_user?
region_ids = user.regions_users.pluck(:region_id)
can :read, Offer, site: { region_id: region_ids }
end
ОБНОВЛЕНИЕ 2
Я мог бы поймать ActiveRecord::RecordNotFound
и raise CanCanCan::AccessDenied
, но это обходной путь. Я ожидаю, что CanCanCan обработает часть авторизации. Я мог бы просто вытащить записи в контроллере и вызвать исключение, но это не имеет отношения к CanCanCan, не так ли?