By default Volt models can be read or edited by anyone, however it is easy to restrict how a model can be read or changed. Volt's permissions API breaks this down in to four different actions: create, read, update, delete (or CRUD)
You specify permissions inside of a model class like so:
class Todo < Volt::Model
permissions do
# .. permissions logic ..
end
end
The permissions block is called anytime one of the CRUD actions happens on the model. Inside of the permissiosn block, you can use allow
and deny
to restrict permissions If you call either without any arguments, then the entire action is blocked. You can instead pass in a list of field names as arguments, then the action will only be blocked for those fields. When run, self
inside of the permission block will be the current model.
class Todo < Volt::Model
permissions do
deny :label
end
end
If the last value in a permissions block (the implicit return) is a Promise, the permissions block will resolve the permissions block before continuing. (So you can query other models inside of permissions blocks, and use .then to return a new promise.
class Todo < Volt::Model
permissions do
# Volt.current_user returns a promsie that resolves the current user, we
# then return a new promise that checks the admin state and denies unless
# the user is an admin.
Volt.current_user.then do |user|
deny unless user.admin?
end
end
end
You can use the own_by_user
method to automatically assign the user_id
field to the logged in user when a model is created (See Users for more info) It will also setup a belongs_to :user (or optionally another key passed in for the user_id
)
If a model is owned by the user, you can check if the currently logged in user is the owner in a permissions block by calling .owner?
Owner will return true if the current user is the owner.
class Todo < Volt::Model
own_by_user
permissions do
deny unless owner?
end
end
^ The above would prevent anyone besides the owner from reading, creating, updating, or deleting this model. (.owner?
returns true in create because own_by_user
will have already assigned the user_id
)
Once one allow is specified, all other fields will be denied. Deny's override allow's.
class Todo < Volt::Model
permissions do
allow :label, :complete
end
end
^ only label and complete would be allowed, all others would be blocked. Using permission
without any arguments will setup permissions for all CRUD operations (create, read, update, delete) To restrict the permissions to only certain actions, you can pass in symbol's for each action as arguments to the permissions
method. You can also specify multiple permission blocks.
class Todo < Volt::Model
permissions(:create, :update) do
deny :notes, :secret_notes unless owner?
end
permissions(:read) do
deny :secret_notes unless owner?
end
permissions(:delete) do
deny unless owner?
end
end
^ The above would allow only the owner to change notes
and secret_notes
, but anyone can change the other fields. Only the owner could read secret_notes
(while all other fields would be able to be read by anyone). And only the owner could delete the model.
You can also pass an action argument to the permission block. This will be a symbol representing the current action that is running.
class Todo < Volt::Model
permissions(:read, :update) do |action|
if action == :read
allow
else
deny unless owner?
end
end
end
Sometimes rather than setting up complex logic in permissions, you can simply deny changes, then only do changes from a task. For example, if you wanted to set an admin
flag on the user model. You could simply deny updates to admin
and then manually set admin by skipping permissions.
class User < Volt::User
permissions(:create, :update) do
# make it so no one can update without skipping permissions
deny :admin
end
end
You can skip permissions by running Volt.skip_permissions
and passing it a block. skip_permissions
can only be run on the server, for obvious reasons.
Volt.skip_permissions do
# Running without permission checks.
# Set admin
user._admin = true
end
The permissions API attempts to provide a simple way to define who can do what to your app's data. You can put any logic inside of the permissions blocks