I'm pretty new to Rails, and I would like to know if there is a way to had an "expired_at" field using the gems "Rolify", so I could add a Role to an User for a while, or permanent Role if field is NULL.
I thought of adding the field into the migration :
class RolifyCreateRoles < ActiveRecord::Migration[6.1]
def change
create_table(:roles) do |t|
t.string :name
t.references :resource, :polymorphic => true
t.timestamps
end
create_table(:users_roles, :id => false) do |t|
t.references :user
t.references :role
t.datetime :expired_at # Adding field to the "join_table"
end
add_index(:roles, [ :name, :resource_type, :resource_id ])
add_index(:users_roles, [ :user_id, :role_id ])
end
end
But I don't have any idea about how to "override" the methods like "add_role" or "has_role?" to take this "expired_at" field into consideration, so I could do something like :
room = Chat::Room.find(1)
sarah = User.find(1)
david = User.find(2)
# Today
sarah.add_role :muted, room, 7.days.from_now
david.add_role :muted, room
sarah.has_role? :muted, room # should return true
david.has_role? :muted, room # should return true
# A week later
sarah.has_role? :muted, room # should return false
david.has_role? :muted, room # should return true
Thanks.
i have an idea that you don't need to add expired_at
field, you can extend rolify
gem to append the expired time after the role name, then we can parse the expired time and check whether that role is expired or not, take a look following code:
# lib/rolify/role.rb
module Rolify
module Role
def add_expire_role(role_name, expire_time, resource = nil)
expire_role_name = "#{role_name} expire_at #{expire_time}"
add_role(expire_role_name, resource)
end
def check_role(role_name, resource = nil)
expire_roles = self.class.adapter.where(self.roles).where("roles.name LIKE ?","%#{role_name}%")
# filter still available roles
avail_roles = expire_roles.select do |role|
_, expire_role_time = role.name.split("expire_at")
expired = expire_role_time.present? && expire_role_time.to_time < Time.now
# remove expired role
self.class.adapter.remove(self, role.name, resource) if expired
!expired
end
# return true if there's still any role
avail_roles.any?
end
end
end
# config/initializers/rolify.rb
Rolify.configure do |config|
# ...
end
Dir[File.join(Rails.root, "lib", "rolify", "**/*.rb")].each {|l| require l }
demo
user = User.first
user.add_expire_role :test, 1.minute.from_now
user.check_role :test # true
# 1 minute later
user.check_role :test # false
user.add_role :test
user.check_role :test # always true
# try override
user.add_expire_role :test, 1.minute.from_now
# 1 minute later
user.check_role :test # still true