Here is a plain-ruby approach for a flexible and expendable authorization solution to authorize actions that a user can?
perform within an account or organization based on their access_level
.
class CreateMembers < ActiveRecord::Migration[6.0]
def change
create_table :members do |t|
t.references :account, null: false, foreign_key: true
t.integer :access_level
t.references :user, foreign_key: true
t.timestamps
end
add_index :members, :access_level
end
end
In a single class Ability
, we have defined a number of class methods to set the permissions. For instance, for a Manager:
# app/models/ability.rb
def manager_rules
@manager_rules ||= staff_rules + [
:edit_post
]
end
Ability
has defined an allowed?
method that check whether a permission exists for a certain object, based on the abilities that you've defined for that class (such as above for a Manager). To make use of a similar syntax as the often-used Cancan authorization gem, you can use a similar can?
method with Ability
:
# app/models/user.rb
def can?(object, action, subject)
Ability.allowed?(self, action, subject)
end
Then all we have to do is check the permission wherever we need it. For instance to check whether someone is allowed to edit a Post:
def destroy
return access_denied! unless can?(current_user, :edit_post, @post)
@post.update(post_params)
redirect_to @post
end
I really like how simple this is. I do have a few questions:
can?
method to be called on an instance of auser
?I think it reads a little better this way, but maybe I'm overlooking why you had an
object
parameter 🤔