How to iterate over all ActiveRecord models

Posted . Visible to the public.

Sometimes you have a maintenance script where you want to iterate over all ActiveRecord models. Rails provides this out of the box:

# script/maintenance_task.rb

# Load all models eagerly, otherwise you might only get a subset
Rails.application.eager_load!

ApplicationRecord.descendants.select(&:table_exists?).each do |model|
  # ...
end

Caution

If you iterate over individual records, please provide a progress indicator: See https://makandracards.com/makandra/625369-upload-run-scripts-production

Caution

At makandra, we use our gem active_type Show archive.org snapshot for model inheritance. Depending on your use case, you might want to skip those models.

Full example

Rails.application.eager_load!

# Inlined here, but if you need this in multiple scripts, prefer the approach from the linked card above
module Enumerable
  def with_progress(title = 'Progress')
    total = count.to_f
    each_with_index do |item, index|
      progress = (index + 1) / total * 100
      printf("#{title}: %.2f%%\r", progress)
      yield item
    end
    puts "#{title} is done."
  end
end

ApplicationRecord.descendants.select(&:table_exists?).each do |model|
  # I wanted to iterate over all models with a CarrierWave uploader
  attributes = model.uploaders.keys
  next if attributes.empty?

  # Skip active_type models
  if model < ActiveType::RecordExtension::Inheritance
    puts "Skipped ActiveType form model #{model}"
    puts
    next
  end

  # Perform your migration with helpful progress output
  puts "Fixing uploads for #{model}: #{attributes.to_json}"

  model.find_each.with_progress(model.to_s) do |record|
    attributes.each do |attribute|
      record.public_send(attribute).my_custom_migration_task!
    end
  end

  puts
end
Profile picture of Klaus Weidinger
Klaus Weidinger
Last edit
Klaus Weidinger
License
Source code in this card is licensed under the MIT License.
Posted by Klaus Weidinger to makandra dev (2025-12-01 09:34)