Search code examples
ruby-on-railscancancancancan

cancancan row based filter


I have declared a role ability in the cancancan gem (rails 5, postgres, devise):

can [:update, :show, :destroy, :index], SalesDatum do |datum|
  datum.try(:user_id) == user.id #the ids just access the id's from the user object that is passed into can can and from the table
end

SalesDatum has a user_id field.

This works on the show actions, because I can only show the SalesDatum that has the logged in user_id For example:

http://localhost:8080/projects/19/sales_data/961 correctly gets authenticated because the logged in user_id matches the user_id on the sales_data

http://localhost:8080/projects/19/sales_data/800 correctly does not get authenticated because the logged in user_id does not match the user_id on the sales_data

However when I go to the get index action: http://localhost:8080/projects/19/sales_data it shows all of the sales data from the @sales_data variable. So, it would show the data.id 800 and 961.

sales data controller:

load_and_authorize_resource
def index
  @sales_data = SalesDatum.where(project_id:params[:project_id])
end

How do I get the index action to only show the data with the relevant user_id? Isn't cancan supposed to filter that according to the user_id?


Solution

  • You need to define the rule with the hash syntax.

    can [:update, :show, :destroy, :index], SalesDatum, user_id: user.id
    

    you may also want to define the edit action and therefore:

    can [:edit, :update, :show, :destroy, :index], SalesDatum, user_id: user.id
    

    which can be simplified into:

    can :manage, SalesDatum, user_id: user.id
    

    if SalesDatum has a belongs_to :user defined you can also write:

    can :manage, SalesDatum, user: user