Skip to content

Instantly share code, notes, and snippets.

@kylefox
Created March 24, 2020 18:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kylefox/59e0b8e72a40859ca0ca6ac3b3a65235 to your computer and use it in GitHub Desktop.
Save kylefox/59e0b8e72a40859ca0ca6ac3b3a65235 to your computer and use it in GitHub Desktop.
Rails controller concern for automatically signing in Devise users after they confirm their email address.
shared_context 'sign in after confirmation' do |resource_name:|
before do
@request.env['devise.mapping'] = Devise.mappings[resource_name]
end
shared_examples 'failed confirmation' do |error:|
it { is_expected.to have_http_status :ok }
it { is_expected.to render_template 'devise/confirmations/new' }
it "has errors on @#{resource_name}" do
subject
expect(assigns[resource_name].errors.full_messages).to eq([error])
end
end
shared_examples 'successful confirmation' do |action:|
it "#{action}s the #{resource_name}" do
message = action == :confirm ? :confirmation_required? : :pending_reconfirmation?
expect { subject }.to(change { resource.reload.send(message) }.from(true).to(false))
end
it 'sets the flash' do
subject
expect(flash[:notice]).to eq I18n.t('devise.confirmations.confirmed')
end
end
shared_examples 'prompted to sign in' do
it { is_expected.to redirect_to send("new_#{resource_name}_session_path") }
it 'does not sign in the user' do
expect { subject }.to_not(change { @controller.send("current_#{resource_name}") }.from(nil))
end
end
end
module SignInAfterConfirmation
extend ActiveSupport::Concern
included do
before_action :set_first_confirmation, only: :show
end
# GET /resource/confirmation?confirmation_token=abcdef
def show
super do |resource|
sign_in(resource) if sign_in_after_confirmation?
end
end
protected
def set_first_confirmation
# Is the User associated with this confirmation_token confirming their address
# for the first time? Or are they RE-confirming an address change?
# If this is the first time confirming, `confirmed_at` will be `nil`.
@first_confirmation = resource_class.where(
confirmation_token: params[:confirmation_token],
confirmed_at: nil
).exists?
end
def sign_in_after_confirmation?
# Devise executes #show when a user first confirms their address (i.e. after sign up)
# AND when a user reconfirms their address (i.e. after changing it).
# For security reasons, never sign in after reconfirmation.
# If the user made a typo when changing their email addres, they have
# inadvertantly given full account access to whoever owns that email address.
# The same problem exists for confirmations, but we're less concerned because
# there's no sensitive data in the account yet (it's brand new).
(
resource.errors.empty? && # Don't sign in invalid users.
@first_confirmation # Don't sign in reconfirmations.
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment