Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I delete an invitation with devise_invitable?

I have devise_invitable installed on my rails application. Creating a new invitation works properly.

I built a view to manage the list of invitations, and created a form button to allow the admin to delete outstanding invitations. Here is the code:

<%= link_to "Cancel Invitation", remove_user_invitation_path(invitation_token: invited.invitation_token), confirm: "Are you sure?", class: 'btn btn-mini btn-danger' %>

The result is always an error "The invitation token provided is not valid!"

Looking at the server logs, I see something like this:

Started GET "/invitation/remove?invitation_token=f4e26062f27c7cc32a60e2024b9dba2b1350abba" for 127.0.0.1 at 2013-10-28 15:07:44 -0700
Processing by Devise::InvitationsController#destroy as HTML
Parameters: {"invitation_token"=>"f4e26062f27c7cc32a60e2024b9dba2b1350abba"}
User Load (2.9ms)  SELECT "users".* FROM "users" WHERE "users"."invitation_token" = '46488d68fb36387ec639d5d6b9749273b56561a944f76eeefb2f5294ea5225e6' LIMIT 1

This suggests that the delete method is not expecting the raw invite token. (I can understand this from a security stand point.)

What value should I be passing to remove_user_invitation_path?

like image 243
cjkaminski Avatar asked Oct 28 '13 22:10

cjkaminski


1 Answers

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.

like image 113
user2256619 Avatar answered Sep 22 '22 21:09

user2256619