This is a plugin for seamless integration of Vue.js application with Rails backend authorization framework CanCan[Can].
yarn add vue-cancan
In your app's entry point file:
import Vue from 'vue'
import VueCanCan from 'vue-cancan'
// window.abilities - are exported JSON abilities from CanCan, read further.
Vue.use(VueCanCan, { rules: window.abilities.rules });
In your routes definition:
import VueRouter from 'vue-router'
import VueCanCan from 'vue-cancan'
const router = new VueRouter({
routes: [
// ...
],
})
// Redirect to root url when user has no rights to see the page
router.beforeEach(VueCanCan.navigationGuard('/'));
From the Rails side everything you need is to pass current_ability's JSON exported rules to the application. You can do it with gem gon
or just with a template:
<script>
window.abilities = <%= current_ability.to_json.html_safe %>
</script>
CanCanCan gem in fresh version provides ability.as_json
method. If for some reason you use older versions, you can add this method to your Ability
class:
def as_json(foo)
rules.map do |rule|
{
base_behavior: rule.base_behavior,
actions: rule.actions.as_json,
subjects: rule.subjects.map(&:to_s),
conditions: rule.conditions.as_json
}
end
end
vue-cancan defines a directive v-can
for templates to check if the user can see the element. It requires two modificators: action and resource name:
<div id='navbar-item' v-can.index.users>
<a href='/admin/users'>Users Administration</a>
</div>
This is equal to Rails erb template:
<% if can? :index, User %>
<div id='navbar-item'>
<a href='/admin/users'>Users Administration</a>
</div>
<% end %>
For more complicated checks you can use v-if
directive with Vue method $can
:
<td v-if="$can('edit', 'users') || $can('destroy', 'users')">User operations</td>
router.beforeEach(VueCanCan.navigationGuard('/'));
This construction adds navigation guard for Router to check if user has access to the URL. It works by parsing requested path and interprets it in this way:
/users/new
will be challenged against $can('new', 'users')
, /users
will be challenged against $can('index', 'users')
.
this.$root.setRules(rulesArray);
You can update the rules from a Vue component.
this._vm.setRules(rulesArray);
Or update the rules from inside of Vuex store.
this._vm.setRules([]);
Or remove the current set of rules as well.
The convention is the same as for Rails' cancan
gem. manage
action covers any possible actions, all
subject covers any possible subjects. Ability to manage
all
- is a superuser ability.
Another alias is read
- it covers index
and show
actions.
Other usual actions in the convention are update
, destroy
, create
. And of course, you can define any other actions.
- Support for abilities conditions and scopes
- Read routes meta to redefine required abilities
- Interface to define abilities client-side