devise_invitable icon indicating copy to clipboard operation
devise_invitable copied to clipboard

undefined method `empty?' for <User> when inviting user who already accepted invitation

Open drale2k opened this issue 3 years ago • 1 comments

When i use the invitation form to invite an user by email who has already accepted the invitation and set his password, i get the following error upon invite form submission.

NoMethodError in Users::InvitationsController#create

undefined method `empty?' for #<User id: 16, ...>

The error stack shows:

activemodel (7.0.3) lib/active_model/attribute_methods.rb:458:in `method_missing'
20:48:13 web.1  | rack (2.2.3.1) lib/rack/etag.rb:69:in `block in digest_body'
20:48:13 web.1  | actionpack (7.0.3) lib/action_dispatch/http/response.rb:146:in `each'
20:48:13 web.1  | actionpack (7.0.3) lib/action_dispatch/http/response.rb:146:in `each_chunk'
20:48:13 web.1  | actionpack (7.0.3) lib/action_dispatch/http/response.rb:128:in `each'
20:48:13 web.1  | actionpack (7.0.3) lib/action_dispatch/http/response.rb:76:in `each'
20:48:13 web.1  | actionpack (7.0.3) lib/action_dispatch/http/response.rb:481:in `each'
...

I would expect a validation to be in place and fail because the email already belongs to an active user.

My InvitationsController looks like this:

class Users::InvitationsController < Devise::InvitationsController
  before_action :configure_permitted_parameters

  def after_invite_path_for(resource)
    users_path
  end

  protected

  # Permit the new params here.
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:invite, keys: [:first_name, :last_name, :role])
  end
end

drale2k avatar Jun 08 '22 14:06 drale2k

Can you remove backtrace silencers, please? I can't see where is calling empty? on User record. The only lines calling a method empty? are invitable.errors.empty? or resource.errors.empty?

scambra avatar Jun 23 '22 13:06 scambra

Having the same issue.

Looks like it is somewhere behind invitable in Rails 7

[activemodel (7.0.4) lib/active_model/attribute_methods.rb:458:in `method_missing']
[rack (2.2.4) lib/rack/etag.rb:71:in `block in digest_body']
[actionpack (7.0.4) lib/action_dispatch/http/response.rb:145:in `each']
[actionpack (7.0.4) lib/action_dispatch/http/response.rb:145:in `each_chunk']
[actionpack (7.0.4) lib/action_dispatch/http/response.rb:127:in `each']
[actionpack (7.0.4) lib/action_dispatch/http/response.rb:75:in `each']
[actionpack (7.0.4) lib/action_dispatch/http/response.rb:480:in `each']
[rack (2.2.4) lib/rack/body_proxy.rb:41:in `method_missing']
[rack (2.2.4) lib/rack/etag.rb:69:in `digest_body']
[rack (2.2.4) lib/rack/etag.rb:33:in `call']
[newrelic_rpm (8.10.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:100:in `call']
[rack (2.2.4) lib/rack/conditional_get.rb:40:in `call']
[newrelic_rpm (8.10.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:100:in `call']
[rack (2.2.4) lib/rack/head.rb:12:in `call']

gryphon avatar Dec 28 '22 11:12 gryphon

It may be simliar to this issue: https://github.com/rack/rack/issues/1725

According to the answer, something is returning the user in the body array which rack gets on line 27: https://github.com/rack/rack/blob/v2.2.5/lib/rack/etag.rb#L27

DeviseInvitable is using respond_with resource, as devise does. Do you have the same issue with registration or sign in for example?

scambra avatar Jan 13 '23 10:01 scambra

respond_with is a method from responders gem, what's the version of responders gem? is it the latest version?

scambra avatar Jan 13 '23 10:01 scambra

I just disable the turbo in the form, adding data: { turbo: false }:

= simple_form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :post }, data: { turbo: false }) do |f|

gordienko avatar Jan 31 '23 17:01 gordienko

I wasn't using the devise_invitable gem but was having the same problem. I had configured the devise parent_controller to be this class:

module Users
  class DeviseController < ApplicationController
    class Responder < ActionController::Responder
      def to_turbo_stream
        controller.render(options.merge(formats: :html))
      rescue ActionView::MissingTemplate => e
        raise e if get?

        if has_errors? && default_action
          render rendering_options.merge(formats: :html, status: :unprocessable_entity)
        else
          redirect_to navigation_location
        end
      end
    end

    self.responder = Responder
    respond_to :html, :turbo_stream
  end
end

The problem was solved by deleting this controller and switching the devise parent_controller back to the ApplicationController

fedegl avatar Feb 25 '23 00:02 fedegl

After "bundle update" today, I had exactly the same issue. Thank you @fedegl, that really helped me, saved a lot of time and got my code back running. I thought I was going crazy for a moment. Thanks a lot.

d33pjs avatar Mar 07 '23 21:03 d33pjs

Closing as it may be caused by custom code. @fedegl thanks for helping with the fix

scambra avatar Mar 08 '23 16:03 scambra

Thanks @fedegl. My experience was similar and I had followed @excid3's tutorial on GoRails to make Devise compatible with Turbo.

This included adding a TurboFailureApp adding a TurboController and adding turbo_stream to the array of respond_to formats. It then set the parent_controller to TurboController.

I removed all that boilerplate from the GoRails fix then followed your suggestion to switch config.parent_controller = 'TurboController' back to ApplicationController. I am back on the road again.

This all happened because I updated ruby to 3.2.1 and did a big bundle update / deleted my Gemfile.lock and re-bundled. Likely getting this commit of devise which made Devise compatible with rails Turbo.

jaykilleen avatar Mar 30 '23 00:03 jaykilleen

Devise is compatible with Turbo out of the box now, so none of those patches are required anymore.

excid3 avatar Mar 30 '23 01:03 excid3