crimata-website/app/controllers/sessions_controller.rb
Andrew Gundersen a1175ab00d Add passwordless email auth with pre-checkout signup
Flow: enter email → magic link → verified → Stripe checkout → dashboard

- SessionsController: new/create (send magic link), sent, verify, destroy
- Customer model: generate_magic_token!, magic_token_valid?, verify_email!
- Migration: magic_token, magic_token_expires_at, email_verified_at + unique indexes
- CustomerMailer + mailer layout with magic link email (html + text)
- CheckoutController: GET /checkout/start requires auth, passes customer_id
  as Stripe metadata; webhook finds customer by metadata and updates record
- DashboardController: requires auth, uses current_customer from session
- ApplicationController: current_customer, require_auth, redirect_after_auth
  (stores return_to so verify sends user back to where they were headed)
- Resend gem + initializer; production uses :resend delivery method
- Dev logs magic link URL to Rails logger instead of sending email
- Pricing page: simple link to /checkout/start (no more JS fetch)
- Layout: Sign in / Dashboard / Sign out nav links

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 17:12:23 -05:00

48 lines
1.2 KiB
Ruby

class SessionsController < ApplicationController
def new
redirect_to dashboard_path if current_customer
end
def create
email = params[:email].to_s.strip.downcase
unless email.match?(URI::MailTo::EMAIL_REGEXP)
flash.now[:alert] = "Please enter a valid email address."
return render :new, status: :unprocessable_entity
end
customer = Customer.find_or_initialize_by(email: email)
customer.generate_magic_token!
CustomerMailer.magic_link(customer).deliver_now
# In development, log the link so you don't need a real email service
if Rails.env.development?
Rails.logger.info "MAGIC LINK: #{verify_url(token: customer.magic_token)}"
end
redirect_to login_sent_path
end
def sent
end
def verify
customer = Customer.find_by(magic_token: params[:token])
if customer.nil? || !customer.magic_token_valid?
flash[:alert] = "That link has expired or is invalid. Request a new one."
return redirect_to login_path
end
customer.verify_email!
session[:customer_id] = customer.id
redirect_after_auth
end
def destroy
session.delete(:customer_id)
redirect_to root_path
end
end