简体   繁体   中英

Rails cancancan fetching records for specific user

I need to fetch only specific records from the database on a certain condition using CanCanCan. This is my data model.

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

For example, a user is assigned to two regions, which means that the user user.regions_users returns and array of two RegionsUser [RegionsUser1, RegionsUser2]. RegionsUser1 belongs to a Region A and RegionsUser2 belongs to Region B so if I am logged in as the user I am a region user that can oversee the data belonging to those regions. Now, I need to display Offers that belong to those regions (Region A and Region B). That means, that the user cannot access an offer belonging to a region other than Region A and Region B, so accessing /offers/3 should raise Access Denied error.

I can pull the regions from RegionsUser:

region_ids = user.regions_users.pluck(:regions_id)

and then the Offers:

Offer.joins(:site).where(sites: { region_id: region_ids })

I read about defining abilities using a block described here

can :update, Project, ["priority < ?", 3] do |project|
  project.priority < 3
end

but I can't think of any solution for my case. I would appreciate any ideas.

UPDATE

This kinda works, but instead of displaying Access Denied page it raises 404 Page Not Found error.

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

UPDATE 2

I could catch ActiveRecord::RecordNotFound and raise CanCanCan::AccessDenied but that is a workaround. I would expect CanCanCan to handle the authorization part. I could just pull the records in the controller and raise an expcetion but that doesn't really relate to CanCanCan, does it?

I think you need load_and_authorize_resource in your controllers. I don't think it will raise the

raise CanCan::AccessDenied.new("Not authorized!", :read, Article) unless you do that. The accessible_by(currrent_ability) simply scoped the result set to those defined in your ability file

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM