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?
also i would like your opinion if this is the right way to go.
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.
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.
Join 30,005+ developers who get early access to new screencasts, articles, guides, updates, and more.