In facture.lu we use Pundit as our authorization system and Devise for authentication. This allows us to assign each signed-in user a role - admins can do everything, read-only user can only read.
I also included View Component in this project as I noticed in previous apps that it is very difficult to maintain a coherent design over the years if the html and css for each component (e.g. a button or dropdown menu) is not centralized.
After setting up Pundit and creating policies for each user role, we can hide or show different elements based on the current user's role - f.ex. the button to add a new team member will only be visible to admins.
In a view we can simply verify if policy(User).create?
and Pundit will call the current_user
method to check if the signed-in user is allowed to perform this action.
In a view component, this does not work out of the box however, as a component is generally agnostic about the view context.
As such policy(current_user, User).create?
will give you an error:
undefined method `current_user' for nil:NilClass
Several solutions to this problem are described in issue#310 (View Component). I prefer the CurrentAttributes api solution described by jaredcwhite.
In order to get our current_user
to our components, we take advantage of ActiveSupport::CurrentAttributes:
class Current < ActiveSupport::CurrentAttributes
attribute :user
end
In an ApplicationController before_action callback, we set the current user:
before_action :initialize_component_context
def initialize_component_context
Current.user = current_user
end
In our view component, we can then access the user via the new class:
Pundit.policy(Current.user, Offer).edit?
In the issue comments, you can read more about how to make it work for previews as well. As I'm not using previews at the moment, I didn't include all the recommendations from the post.
Top comments (0)