15

I am using devise confirmable. I have some custom things that i need to override from devise's confirm! method, so in my user model i have the following method that overrides it:

def confirm!
  super
  gb = Gibbon::API.new(ENV['MAILCHIMP_API_KEY'])
  gb.lists.subscribe({:id => ENV['MAILCHIMP_ID'], :email => {:email => self.email }})
end

This works perfectly. Now I am trying to have it so the user is automatically signed in after confirming, but cannot figure out how. I know that this is considered a security flaw, but I have weighed the risks and it is worth it for user experience in my site. I do not want to do anything with the routes file because this method is already working, so i should be able to do it from here. I have tried putting the following into my configuration file:

config.allow_insecure_sign_in_after_confirmation = true

but it does not sign the user in.

I've looked at the stack overflow page at Avoid sign-in after confirmation link click using devise gem? and it does not help so please don't mark this as a duplicate.

Thanks everyone.

Community
  • 1
  • 1
Philip7899
  • 4,599
  • 4
  • 55
  • 114
  • Are you sure you read the second answer there? It seems to have a solution that I would think works for you: http://stackoverflow.com/a/20961042/897414 – Bryan Clark Aug 11 '14 at 22:57
  • Yes, I read it, but that would involve changing the entire new confirm! method I created which already works. I want to somehow call sign_in from the method i wrote above. – Philip7899 Aug 11 '14 at 23:43
  • Any ideas - i can't figure this out? – Philip7899 Aug 13 '14 at 17:23
  • You can't sign a user in from the model, it has to be in the controller which has access to the request and session cookies. – Bryan Clark Aug 14 '14 at 15:09
  • As Brian implied, the solution suggested in the other question's 2nd answer doesn't involve any changes to your overridden `confirm!` (unless I'm missing something a bit subtle); instead it subclasses the `Devise::ConfirmationsController` and overrides `show`. – Tim Aug 16 '14 at 22:44
  • oh, i see. Bryan, you're right, the controller method works. I just did not understand without Tim's explanation. – Philip7899 Aug 29 '14 at 19:44

2 Answers2

28

You would change routes.rb and controllers/users/confirmations_controller.rb (maybe default path)

routes.rb to mapping users/confrimations_controller

devise_for :users, controllers: {confirmations: 'users/confirmations'}

confirmations_controller to automatically sign in and redirect to

def after_confirmation_path_for(resource_name, resource)
  sign_in(resource)
  any_path # redirect_to is not necessary
end
Carl Edwards
  • 13,826
  • 11
  • 57
  • 119
ogelacinyc
  • 1,272
  • 15
  • 30
  • 1
    sign_in(resource) must be in show method of confirmations_controller, method after_confirmation_path_for must contain only the path! – maricavor Mar 18 '19 at 13:32
12

Generate the controller:

rails generate devise:controllers users -c=confirmations

Amend routes:

devise_for :users, controllers: {confirmations: 'users/confirmations'}

Then overwrite the show method:

  # app/controllers/users/confirmations_controller.rb
  def show
    super do
      sign_in(resource) if resource.errors.empty?
    end
  end

  def after_confirmation_path_for(resource_name, resource)
    after_sign_in_path_for(resource)
  end
Ivan
  • 3,187
  • 1
  • 19
  • 16
maricavor
  • 188
  • 2
  • 10
  • 1
    This was exactly what I am looking for, although `after_confirmation_path_for` was not required for me. – Tashi Dendup Mar 12 '20 at 12:38
  • Overwrite the `after_confirmation_path_for` method is not needed in this case because when you call the `sign_in` (or `sign_out`) method, the `SessionsController` is in charge of the redirections. – Franchy Oct 14 '20 at 16:15