I'm building the exact same thing at the moment, and ran into the same issue.
What I found is that when Devise-Invitable accept link tokens are actually are an encrypted version of the 'raw' token. The raw token is not persisted - its an instance variable on the (invited) user object. (see generate_invitation_token() in lib/devise_invitable/model.rb )
Since you're already on the listing page, that original user object is long gone, and all you have left is what was persisted.
I see a few ways around this - either persist the raw_invitation_token when the user is invited. (You might do this by adding another column to your user, and overriding the relevant invite() method. This gets nasty quickly with multiple saves or a tempting monkey patch.)
I started down route and got about 90% of the way there before I realized that even if you get this to work, the standard remove endpoint actually expects a user to not be logged in, which forced me to rethink why I need to reuse that route anyway?
So my current solution involves a new endpoint, which 1) uses a different finder method besides User.find_by_invitation_token() (it decrypts the token), and doesnt check that you're logged out :-)
eg.
class InvitationsController < ApplicationController
...
before_filter :user_from_invitation_token
def remove
User.destroy(@user.id)
flash[:notice] = 'Invitation removed'
redirect_to company_users_path
end
private
def user_from_invitation_token
unless params[:invitation_token] && @user = @company.invited_users.where(invitation_token: params[:invitation_token]).first
flash[:error] = 'Invitation not found'
redirect_to company_users_path
end
end
...
This is a WIP and I'm not 100% satisfied with the solution - however it makes sense that if you are building a UI for managing invitations, then you're stepping beyond what Devise-invitable provides out of the box.