user2860931 user2860931 - 6 months ago 42
Ruby Question

Rails 4 - Devise - Confirmable subject to approval

I'm trying to learn how to read rubydocs. I'm sure there is something fundamentally basic that I have missed in trying to use these documents, but for now, I'm so frustrated that information is being presented to me, but without any form of intelligible user guide that goes along with it.

I want to amend my devise, so that users can nominate a group they want to join - in this case, an organisation where their email is changed to an organisation email, pending confirmation by the organisation owner.

I think this function (which I have copied below from the devise ruby docs) is going to help.

#postpone_email_change_until_confirmation_and_regenerate_confirmation_token ⇒ Object (protected)

253
# File 'lib/devise/models/confirmable.rb', line 247

def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
@reconfirmation_required = true
self.unconfirmed_email = self.email
self.email = self.email_was
self.confirmation_token = nil
generate_confirmation_token
end


My problem is that I don't understand how it works or how to incorporate it in my app.

Do I add it to my user model (just copy & paste) and then put a line in my user controller for the update action, so that any change of email does each of those the steps listed in the method?

If I do that, what name do I give to the controller call?

In user.rb I have tried:

def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
@reconfirmation_required = true
self.unconfirmed_email = self.email
self.email = self.email_was
self.confirmation_token = nil
generate_confirmation_token
end


In user controller - update action, I have tried:

if @user.update(user_params)
user.postpone_email_change_until_confirmation_and_regenerate_confirmation_token


Im clearly trying to do this incorrectly. What's not clear to me is how I'm supposed to use this function.

Can anyone see where I've gone wrong?

Answer

That method is in Confirmable concern. So, all you need is to define it inside your user.rb

For example

# Extensions
devise :database_authenticatable, :registerable, :confirmable,
       :recoverable, :rememberable, :trackable, :validatable, 
       :lastseenable, :timeoutable

Consider to the :confirmable symbol.

Then if you will change email before_update and after_commit callbacks will be called if all conditions will return true value

You can't call protected instance method from anywhere.

In case of protected methods, you can call them from the scope of any object belonging to the same class. This means that when you pass a Person object p1 as an argument to a method on another Person object p2, you can access all the protected methods of p1 within that method.

from here

module Confirmable
  extend ActiveSupport::Concern

  included do
    # ...
    after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
    after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
    #...
    before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_email_change?
  end

here is a place where callback is called.

And then devise will send reconfirmation email to user.unconfirmed_email

You may need to override reconfirmation instructions email. Here is an example:

# app/mailers/devise/mailer.rb

if defined?(ActionMailer)
  class Devise::Mailer < Devise.parent_mailer.constantize
    include Devise::Mailers::Helpers

    def confirmation_instructions(record, token, opts = {})
      @token = token
      if record.pending_reconfirmation?
        devise_mail(record, :reconfirmation_instructions, opts)
      else
        devise_mail(record, :confirmation_instructions, opts)
      end
    end
  end
end

And the mailer view

# app/views/devise/reconfirmation_instructions.text.erb

Hello, <%= @resource.fullname %>!

Please reconfirm your new email: <%= your_url_with_@token" %>

--
WBR, support team

Hope that helps.

UPDATE

All you need to enable confirmation/reconfirmation is just to add needed strategy to your User model

devise :database_authenticatable, :registerable, :confirmable,
       :recoverable, :rememberable, :trackable, :validatable, 
       :lastseenable, :timeoutable

And override devise mailer

# app/mailers/devise/mailer.rb

if defined?(ActionMailer)
  class Devise::Mailer < Devise.parent_mailer.constantize
    include Devise::Mailers::Helpers

    def confirmation_instructions(record, token, opts = {})
      @token = token
      if record.pending_reconfirmation?
        devise_mail(record, :reconfirmation_instructions, opts)
      else
        devise_mail(record, :confirmation_instructions, opts)
      end
    end
  end
end