How can I use Cancan permissions to filter the papertrail versions that I retrieve for a timeline?

473 views Asked by At

I have a few models with version changes I am tracking using Papertrail. I want to pull out the version for a timeline view of recent activity, but users should only see changes to models which they have permission to view.

I use Cancan to control access to all areas of the app, and the Ability class has all the business logic I need. However, it specifies the model name e.g. Post in the rulesets, whereas PaperTrail uses the Version model to store changes.

How can I (efficiently) tie the two systems together so that I can ask the DB to only return Version models where the associated model is visible to the user? I can do this by just getting the whole timeline of the whole site and looping over it in Ruby, but this is not scalable and I need to use scopes so that it happens in SQL.

1

There are 1 answers

2
Jaap Haagmans On

A version is also an ActiveRecord model. That means you can incorporate it into your Ability class. You can simply do object.versions.accessible_by(current_ability) after you've made sure your Ability properly authorizes versions.

An example could be:

can :read, Version do |version|
  ((version.item_type == 'Client') && (Client.find(version.item_id).account_manager_id == user.id)) ||
  ((version.item_type == 'Project') && (Project.find(version.item_id).allowed_users.map(&:id).include? user.id) )
end

This can, of course, be simplified by using version.item, but then you'll have to delegate the authorization check to another resource (which would enable you to simply say can? :read, version.item). This may or may not suit your specific situation. The method above provides more flexibility.