Ask A Question

Notifications

You’re not receiving notifications from this thread.

Pundit Scope and has_many through

Wouter van den Beld asked in Rails

Hi!

I can use a little help to get on the right track.

I have 3 models

class User < ActiveRecord::Base
  has_many :associations
  has_many :items, through: :associations
end

class Item < ActiveRecord::Base
   has_many :associations
   has_many :users, through: :associations
end

class Association < ActiveRecord::Base
    belongs_to :user
    belongs_to :item
end

Now i want to allow my users only to view and edit the item if they have a link trough associations.
so in my ItemPolicy i have the following scope

 class Scope < Scope
    def resolve
     if user.admin?
        scope.all
      else
        scope.where(:company_id => user.associations.select(:item_id))
      end
    end
  end

I setup my items_controller

def index
  @items = policy_scope(Item.includes(:company).all)
  authorize @items
end

and this works. i only see the items where i have a association. Now i want to prevent users to edit the urllike myapp.com/item/2 and still be able to view item 2 if there is no association.

So i setup my show in the controller:

def show
    @item = policy_scope(Item.find(params[:id]))
    authorize @item
end

but now i get undefined method `where' error. why does the same thing work for index and not for show?
any ideas?

also i would like your opinion if this is the right way to go.

Reply

I think that's because on the index you want an array of records, but on show you just want a single record.

When you pass in the array into policy_scope, it's going to call the .where(company_id: X) method on it. This works when you return Item.all but when you pass in just an Item record, that does not have a where method because it's a single instance of the Item class.

In your show action, you can change it to:

def show
    @item = Item.find(params[:id])
    authorize @item
end

And this will load the record and Pundit will know to authorize it against the right method in the policy without hitting the Scope.

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 85,376+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.