Generating a unique token for invitation system. Anything I'm missing?

before_validation :generate_token, on: :create, if: :token_blank?

private

def generate_token
  self.token = SecureRandom.hex(32)
end

There’s a unique index on the database field itself (using migration) - but on the model this is all I have.

Anything I should add to make this more robust?

If you are using Rails 7.1, rails adds the method generates_token_for.

Your model could look like this:

class User < ActiveRecord::Base
  generates_token_for :invitation_token
end

You can get new token by calling:

token = User.first.generate_token_for(:invitation_token)

You can find a user by this token:

user = User.find_by_token_for(:invitation_token, token)

Note that you don’t have to create additional database field. The best part

Check: ActiveRecord::TokenFor::ClassMethods - Ruby on Rails API

2 Likes

Thank you, that worked beautifully! Bonus: no need for another database field!

You can use a GUID, it’s even a good idea. Just make sure your GUID generator is using a cryptographically secure random number generator.

Note that you don’t have to create additional database field. The best part

You don’t have create a database field?

How would you assert / compare that the token is correct or valid not? I would be very interested to know more.

Update: you are right. thanks for the pointer. It saves me from keeping an uneeded database field/

@BenKoshy I have a complete explanation of how this feature works in another thread in the here:

The basic idea is that the method uses the record id and the name you pass it to generate an encrypted value, that it can then decrypt and compare back with the id. You can even pass it a block with some additional data for verification. This is useful if you want the token to stop working after something changes in the record.

1 Like