devise_invitable icon indicating copy to clipboard operation
devise_invitable copied to clipboard

Inviting a user just redirects to main page with a message that "the user is already logged in"

Open holgersindbaek opened this issue 10 years ago • 10 comments

I'm having a strange error and it only happens with one user (I've tested it with several).

When I login an try to invite another user, I simply get redirected to the root url, with a message saying I'm already logged in. The create method, doesn't even get touched.

In the console, I get the error "Filter chain halted as :require_no_authentication rendered or redirected".

Any suggestions on what might be happening?

Stack trace:

Started PUT "/users/invitation" for 127.0.0.1 at 2014-08-12 16:25:37 +0200
Processing by Users::InvitationsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"0jcXaiqyytJWLv5PopyGG0Ptquc+eT/s7xagdEB56A8=", "user"=>{"first_name"=>"", "last_name"=>"", "role"=>"team_member", "email"=>"", "team_name_one"=>"", "team_name_two"=>"", "make_admin"=>"1"}, "commit"=>"Invitér bruger"}
  MOPED: 127.0.0.1:27017 QUERY        database=vsa-web-app collection=users selector={"$query"=>{"_id"=>"53cadfcdb56c2fd077000003"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil (0.4039ms)
Redirected to http://localhost:3000/
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 1.9ms

Controller:

class Users::InvitationsController < DeviseController

  prepend_before_filter :authenticate_inviter!, :only => [:new, :create]
  prepend_before_filter :has_invitations_left?, :only => [:create]
  prepend_before_filter :require_no_authentication, :only => [:edit, :update, :destroy]
  prepend_before_filter :resource_from_invitation_token, :only => [:edit, :destroy]
  helper_method :after_sign_in_path_for

  # GET /resource/invitation/new
  def new
    @new_user_role = new_user_role
    @institution = current_inviter.institution
    @team = current_inviter.team

    self.resource = resource_class.new
    render :new
  end

  # POST /resource/invitation
  def create
    # Make institution name be correct name
    if !params[:user][:institution_name_one].blank? || !params[:user][:institution_name_two].blank?
      params[:user][:institution_name] = Institution.find(params[:user][:institution_name_one]).name.capitalize unless params[:user][:institution_name_one].blank?
      params[:user][:institution_name] = params[:user][:institution_name_two].capitalize unless params[:user][:institution_name_two].blank?
    end

    # Make team name be correct name
    if !params[:user][:team_name_one].blank? || !params[:user][:team_name_two].blank?
      params[:user][:institution_name] = current_inviter.institution ? current_inviter.institution.name : current_inviter.institution_name
      params[:user][:team_name] = Team.find(params[:user][:team_name_one]).name.capitalize unless params[:user][:team_name_one].blank?
      params[:user][:team_name] = params[:user][:team_name_two].capitalize unless params[:user][:team_name_two].blank?
    end

    # Set resource to parameters
    self.resource = invite_resource

    # Save invitation
    if resource.errors.empty?
      yield resource if block_given?
      set_flash_message :notice, :send_instructions, :email => self.resource.email if self.resource.invitation_sent_at
      respond_with resource, :location => after_invite_path_for(resource)
    else
      respond_with_navigational(resource) { render :new }
    end
  end


  # GET /resource/invitation/accept?invitation_token=abcdef
  def edit
    resource.invitation_token = params[:invitation_token]
    render :edit
  end

  # PUT /resource/invitation
  def update
    self.resource = accept_resource

    if resource.errors.empty?
      yield resource if block_given?
      flash_message = resource.active_for_authentication? ? :updated : :updated_not_active

      # If user updated and he is an institution admin, then assign him an institution, else assign him a team
      if flash_message==:updated && resource.role=="institution_admin"
        institution = Institution.where(:name => resource.institution_name.capitalize).first
        institution = Institution.create(:name => resource.institution_name.capitalize) unless institution
        institution.users << resource
      elsif flash_message==:updated && (resource.role=="team_admin" || resource.role=="team_member")
        institution = Institution.where(:name => resource.institution_name.capitalize).first
        first_team = Team.where(:name => resource.team_name.capitalize).first
        if first_team
          team = first_team
        else
          team = Team.create(:name => resource.team_name.capitalize)
        end
        team.users << resource
        team.institution = institution if institution
        institution.teams << team if institution

        # Create first documents
        unless first_team
          team.documents.create(:active => true, :role => "teaching_environments", :saved_by => resource.first_name+" "+resource.last_name)
          team.documents.create(:active => true, :role => "evaluation_and_feedback", :saved_by => resource.first_name+" "+resource.last_name)
          team.documents.create(:active => true, :role => "personal", :saved_by => resource.first_name+" "+resource.last_name)
          team.documents.create(:active => true, :role => "open_school", :saved_by => resource.first_name+" "+resource.last_name)
          team.documents.create(:active => true, :role => "purpose_teaching_and_education", :saved_by => resource.first_name+" "+resource.last_name)
          team.documents.create(:active => true, :role => "students_and_parents", :saved_by => resource.first_name+" "+resource.last_name)
        end
      end
      set_flash_message :notice, flash_message
      sign_in(resource_name, resource)
      respond_with resource, :location => after_accept_path_for(resource)
    else
      respond_with_navigational(resource){ render :edit }
    end
  end

  # GET /resource/invitation/remove?invitation_token=abcdef
  def destroy
    resource.destroy
    set_flash_message :notice, :invitation_removed
    redirect_to :back
  end

  def new_user_role
    if current_inviter.role=="project_owner"
      return "institution_admin"
    elsif current_inviter.role=="institution_admin"
      return "team_admin"
    elsif current_inviter.role=="team_admin"
      return "team_member"
    end
  end

  protected

  def invite_resource(&block)
    resource_class.invite!(invite_params, current_inviter, &block)
  end

  def accept_resource
    resource_class.accept_invitation!(update_resource_params)
  end

  def current_inviter
    authenticate_inviter!
  end

  def has_invitations_left?
    unless current_inviter.nil? || current_inviter.has_invitations_left?
      self.resource = resource_class.new
      set_flash_message :alert, :no_invitations_remaining
      respond_with_navigational(resource) { render :new }
    end
  end

  def resource_from_invitation_token
    unless params[:invitation_token] && self.resource = resource_class.find_by_invitation_token(params[:invitation_token], true)
      set_flash_message(:alert, :invitation_token_invalid)
      redirect_to after_sign_out_path_for(resource_name)
    end
  end

  def invite_params
    devise_parameter_sanitizer.sanitize(:invite)
  end

  def update_resource_params
    devise_parameter_sanitizer.sanitize(:accept_invitation)
  end

  def after_invite_path_for(resource)
    new_user_invitation_path
  end

end

holgersindbaek avatar Aug 12 '14 14:08 holgersindbaek

No clues anybody? I'm kind of lost here!

holgersindbaek avatar Aug 14 '14 22:08 holgersindbaek

You are sending form with PUT, which is update action (accept invitation) instead of create action (invite). Did you change invite view?

scambra avatar Aug 18 '14 08:08 scambra

Thanks for the response... I am sending it with put:

    = simple_form_for @plan, :html => {:method => :put} do |f|
      .col-sm-3
        .form-group
          = f.input :name, placeholder: "Plan navn (eks. 4b)", label: false, input_html: { class: 'form-control' }
      .col-sm-3
          = f.button :submit, 'Gem navn', :class => 'btn btn-primary btn-block'
    .col-sm-6
      a.pull-right data-container="body" data-content="Her kan du invitere og administrere gruppens brugere." data-placement="left" data-toggle="popover" data-trigger="hover"
        img alt="Forklaring" height="35" src="#{asset_path '[email protected]'}" width="35"
    .col-sm-12
        hr.clearfix

Should I just take away ", :html => {:method => :put}" and it should work?

holgersindbaek avatar Aug 18 '14 09:08 holgersindbaek

Probably. form_for uses :put if @plan is persisted, :post in other case, I guess simple_form_for does it in same way

scambra avatar Aug 18 '14 14:08 scambra

I still seem to have the same issue. This is my routes file for devise invitable:

devise_for :users, :controllers => { :invitations => 'users/invitations' }
resources :users, except: [:new, :create, :destroy] do
  get 'request_invitation', on: :collection
  post 'send_invitation', on: :collection
  get 'make_admin', on: :member
end

Does everything look good to you?

I tried both deleting the method :put and replacing it with post, but nothing seems to work. Any suggestions?

holgersindbaek avatar Aug 18 '14 17:08 holgersindbaek

It's not a routes issue. This is request:

Started PUT "/users/invitation" for 127.0.0.1 at 2014-08-12 16:25:37 +0200 Processing by Users::InvitationsController#update as HTML

It's a request to update action, because HTTP method is PUT. That's usual behavior. If removing :method => :put doesn't work, try adding :method => :post

Or maybe you posted wrong view, because I see record hash with 7 parameters in request, but form only has name input for @plan.

scambra avatar Aug 19 '14 06:08 scambra

Background

  • resource is the new record created when you invite, e.g. User.create
  • current_inviter is the current user, commonly referred to as current_user
class Devise::InvitationsController < DeviseController
  # ...
  def create
    # ...
    respond_with resource, :location => after_invite_path_for(resource)

This bug is occurring because the code is trying to redirect to after_invite_path_for based on resource when it should more correctly be

    respond_with resource, :location => after_invite_path_for(current_inviter)

It works for most people likely because after_sign_in_path_for or after_invite_path_for does not change based on the argument. For our app (and probably yours), you look at the current instance and redirect to the appropriate route

choonkeat avatar Dec 11 '14 07:12 choonkeat

Apologies, seems it'll take considerable effort to add a PR with test, so here is the workaround instead.

Override default controller and fix the after_invite_path_for

class Users::InvitationsController < Devise::InvitationsController
  def after_invite_path_for(resource)
    after_sign_in_path_for(current_inviter)
  end
end

choonkeat avatar Dec 11 '14 08:12 choonkeat

This happens for GET requests too:

Started GET "/devise/users/invitation/accept?invitation_token=cmkv-2--HpJDJxBBz5Xa" for 10.0.2.2 at 2019-03-11 13:17:56 +0000
Processing by InvitationsController#edit as JSON
  Parameters: {"invitation_token"=>"cmkv-2--HpJDJxBBz5Xa"}
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."invitation_token" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["invitation_token", "bb8e74deadcc5039735d1e1927ce483be7b8cb5a247a3e8004bf3bae65b40cc7"], ["LIMIT", 1]]
  ↳ /usr/lib/ruby/vendor_ruby/phusion_passenger/rack/thread_handler_extension.rb:97
Redirected to http://localhost:3000/
Filter chain halted as :resource_from_invitation_token rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.5ms)

Though it seems to only happen for certain invitations. Over a 3 day period I only had this happen for one specific user invite. I ended up deleting that user and making a new invitation and it went back to working as expected 🤷‍♂️

rally25rs avatar Mar 11 '19 13:03 rally25rs

Same issue here as @rally25rs and I can't understand why it happens for certain invites only. 🤷‍♂️ @rally25rs did you managet to find a root cause?

khalilovcmd avatar Jul 18 '22 15:07 khalilovcmd