Migrating from Custom Rails to Jumpstart Pro
medium
20 hours
rails
ruby
multitenancy
payments

Migrating from Custom Rails to Jumpstart Pro

Upgrade your custom Rails app to Jumpstart Pro for built-in multitenancy, payments, and authentication that just works.

Prerequisites

  • Familiarity with Ruby on Rails conventions
  • Understanding of your current Rails application structure
  • Basic knowledge of database migrations
  • Active Jumpstart Pro license

Migrating from Custom Rails to Jumpstart Pro

If you've built a custom Rails SaaS and want to standardize on a proven foundation, Jumpstart Pro offers authentication, payments, multitenancy, and admin features out of the box. This guide walks you through migrating your existing app.

Why Migrate?#

You might want to migrate if you need:

  • Battle-tested authentication (Devise with social logins)
  • Stripe/Paddle/Braintree payments already wired up
  • Account/team multitenancy with invitations
  • Admin dashboard with Administrate
  • Hotwire/Turbo integration done right
  • Regular security updates

Stay with custom Rails if:

  • Your app is very simple (no payments, no teams)
  • You have highly custom auth requirements
  • You're too deep into a different payment system
  • Migration cost outweighs benefits

Migration Overview#

AspectCustom RailsJumpstart Pro
AuthCustom/DeviseDevise + OmniAuth
PaymentsCustom/NonePay gem (Stripe, Paddle, Braintree)
MultitenancyCustom/NoneActs as Tenant + Account model
AdminCustom/NoneAdministrate
FrontendVariesHotwire, Tailwind CSS
Background JobsVariesSidekiq

Step 1: Set Up Jumpstart Pro#

# Clone your Jumpstart Pro repo
git clone git@github.com:your-username/jumpstart-pro.git my-app-v2
cd my-app-v2

# Install dependencies
bundle install
yarn install

# Set up database
rails db:create db:migrate

# Start the server to verify it works
bin/dev

Step 2: Plan Your Data Migration#

Inventory Your Models#

# List your current models
ls -la app/models/

# Generate a model dependency graph (optional)
rails erd

Map to Jumpstart Pro Conventions#

Your ModelJumpstart Pro Equivalent
UserUser (keep, but update)
Team/OrganizationAccount
MembershipAccountUser
SubscriptionPay::Subscription
PlanPlan
Custom modelsCopy directly

Step 3: Migrate User Data#

Jumpstart Pro uses Devise with additional fields:

Your Current User Model#

# Your app/models/user.rb
class User < ApplicationRecord
  has_secure_password  # or devise
  has_many :projects
  has_many :subscriptions
end

Jumpstart Pro User Model#

# Jumpstart Pro app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         :confirmable, :lockable, :trackable, :omniauthable

  has_many :account_users, dependent: :destroy
  has_many :accounts, through: :account_users
  has_one :personal_account, -> { where(personal: true) }, class_name: "Account"

  # Pay gem for payments
  pay_customer
end

Migration Script#

# lib/tasks/migrate_users.rake
namespace :migrate do
  desc "Migrate users from old app"
  task users: :environment do
    # Connect to old database
    OldUser = Class.new(ApplicationRecord) do
      self.table_name = 'old_users'
      establish_connection(
        adapter: 'postgresql',
        database: 'old_app_production'
      )
    end

    OldUser.find_each do |old_user|
      # Create user in Jumpstart Pro
      user = User.new(
        email: old_user.email,
        password: SecureRandom.hex(16), # They'll need to reset
        first_name: old_user.name&.split(' ')&.first,
        last_name: old_user.name&.split(' ')&.last,
        confirmed_at: old_user.email_verified_at || Time.current
      )

      # Skip validation for migrated users
      user.save!(validate: false)

      # Create personal account
      account = user.create_personal_account!(name: "Personal")

      # If they had a subscription, we'll handle that separately
      puts "Migrated user: #{user.email}"
    end

    puts "Migration complete!"
  end
end

Step 4: Migrate Teams/Organizations to Accounts#

Jumpstart Pro uses Account for multitenancy:

# lib/tasks/migrate_teams.rake
namespace :migrate do
  desc "Migrate teams to accounts"
  task teams: :environment do
    OldTeam = Class.new(ApplicationRecord) do
      self.table_name = 'old_teams'
      establish_connection(...)
    end

    OldTeam.find_each do |old_team|
      # Find the owner
      owner = User.find_by(email: old_team.owner_email)
      next unless owner

      # Create account
      account = Account.create!(
        name: old_team.name,
        owner: owner,
        personal: false
      )

      # Add team members
      old_team.members.each do |member|
        user = User.find_by(email: member.email)
        next unless user

        AccountUser.create!(
          account: account,
          user: user,
          roles: { admin: member.role == 'admin' }
        )
      end

      puts "Migrated team: #{account.name}"
    end
  end
end

Step 5: Migrate Payments#

Jumpstart Pro uses the Pay gem for payments:

If You Had Custom Stripe Integration#

# lib/tasks/migrate_subscriptions.rake
namespace :migrate do
  desc "Migrate Stripe subscriptions"
  task subscriptions: :environment do
    OldSubscription = Class.new(ApplicationRecord) do
      self.table_name = 'old_subscriptions'
      establish_connection(...)
    end

    OldSubscription.where(status: 'active').find_each do |old_sub|
      user = User.find_by(email: old_sub.user_email)
      next unless user

      # Pay gem creates Pay::Customer records automatically
      # We need to sync the existing Stripe data

      # Create Pay::Customer
      pay_customer = Pay::Customer.find_or_create_by!(
        owner: user,
        processor: :stripe,
        processor_id: old_sub.stripe_customer_id
      )

      # Create Pay::Subscription
      Pay::Subscription.create!(
        customer: pay_customer,
        processor: :stripe,
        processor_id: old_sub.stripe_subscription_id,
        processor_plan: old_sub.stripe_price_id,
        status: old_sub.status,
        current_period_start: old_sub.current_period_start,
        current_period_end: old_sub.current_period_end
      )

      puts "Migrated subscription for: #{user.email}"
    end
  end
end

Update Stripe Webhooks#

Point your Stripe webhook to the new endpoint:

https://your-new-app.com/pay/webhooks/stripe

Step 6: Migrate Custom Models#

Copy your business models and update relationships:

Before (Custom Rails)#

# app/models/project.rb
class Project < ApplicationRecord
  belongs_to :user
  belongs_to :team, optional: true
end

After (Jumpstart Pro)#

# app/models/project.rb
class Project < ApplicationRecord
  belongs_to :account  # Use account instead of team
  belongs_to :user, optional: true  # Creator, if needed

  # Acts as Tenant scoping
  acts_as_tenant :account
end

Run the migration#

# db/migrate/xxx_update_projects_for_jumpstart.rb
class UpdateProjectsForJumpstart < ActiveRecord::Migration[7.0]
  def change
    # Add account reference
    add_reference :projects, :account, foreign_key: true

    # Migrate data
    reversible do |dir|
      dir.up do
        Project.find_each do |project|
          # Find account from old team or user
          if project.team_id
            account = Account.find_by(old_team_id: project.team_id)
          else
            account = User.find(project.user_id).personal_account
          end
          project.update!(account: account)
        end
      end
    end

    # Remove old columns
    remove_column :projects, :team_id
  end
end

Step 7: Update Controllers#

Jumpstart Pro provides helper methods for current account:

Before#

class ProjectsController < ApplicationController
  before_action :authenticate_user!

  def index
    @projects = current_user.team.projects
  end
end

After#

class ProjectsController < ApplicationController
  before_action :authenticate_user!

  def index
    # current_account is provided by Jumpstart Pro
    @projects = current_account.projects
  end
end

Step 8: Update Views#

Jumpstart Pro uses Tailwind CSS and ViewComponent:

Migrate to Tailwind#

If your old app used Bootstrap or custom CSS:

<!-- Before (Bootstrap) -->
<div class="card">
  <div class="card-body">
    <h5 class="card-title"><%= @project.name %></h5>
  </div>
</div>

<!-- After (Tailwind) -->
<div class="bg-white rounded-lg shadow p-6">
  <h5 class="text-lg font-semibold text-gray-900"><%= @project.name %></h5>
</div>

Use Jumpstart Pro Components#

<!-- Jumpstart Pro provides styled components -->
<%= render "shared/card" do %>
  <h5 class="text-lg font-semibold"><%= @project.name %></h5>
<% end %>

Step 9: Set Up Background Jobs#

Jumpstart Pro uses Sidekiq:

# Move your jobs to app/jobs/
# Update ActiveJob queue adapter if needed

# config/application.rb
config.active_job.queue_adapter = :sidekiq

Testing Checklist#

  • User sign up and sign in
  • Social logins (Google, GitHub, etc.)
  • Password reset
  • Email confirmation
  • Account creation and switching
  • Team invitations
  • Subscription checkout
  • Subscription management
  • Webhooks receiving
  • All custom features work
  • Background jobs process

Common Challenges#

1. Password Migration#

Problem: Can't migrate hashed passwords between different systems.

Solution: Force password reset for all users:

# Send reset emails after migration
User.find_each do |user|
  user.send_reset_password_instructions
end

2. Different Devise Configuration#

Problem: Your Devise setup differs from Jumpstart Pro's.

Solution: Carefully merge configurations in config/initializers/devise.rb.

3. Tenancy Scoping#

Problem: Queries aren't scoped to current account.

Solution: Ensure all models have acts_as_tenant :account and you're setting current_account properly.

Timeline Estimate#

PhaseEstimated Time
Setup & Planning2 hours
User Migration3 hours
Team/Account Migration3 hours
Payment Migration4 hours
Custom Model Migration4 hours
View/Controller Updates2 hours
Testing2 hours
Total~20 hours

Conclusion#

Migrating to Jumpstart Pro gives you a solid, maintained foundation for your Rails SaaS. The investment pays off in reduced maintenance, security updates, and battle-tested patterns. Focus your energy on what makes your product unique, not on reinventing authentication and payments.

#rails#ruby#multitenancy#payments

Not sure which boilerplate to choose?

Take our 2-minute quiz and get personalized recommendations.

Take the Quiz
Migrating from Custom Rails to Jumpstart Pro | MyStarterStack