You could use UrlStore https://github.com/grosser/url_store and just encode user id and expiration time inside the url, no new columns needed. Only drawback is that the token gets longer.
code = UrlStore.encode([user.id, 2.hours.from_now])
...
if id, expires = UrlStore.decode(params[:id])
if expires > Time.zone.now
...
You could use UrlStore https://github.com/grosser/url_store and just encode user id and expiration time inside the url, no new columns needed. Only drawback is that the token gets longer.