Rolify: Add Expire Datetime

175 views Asked by At

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.

1

There are 1 answers

1
Lam Phan On BEST ANSWER

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