class CreatePostVersions < ActiveRecord::Migration[8.0] class Post < ApplicationRecord self.table_name = 'posts' end class PostTag < ApplicationRecord self.table_name = 'post_tags' end class PostVersion < ApplicationRecord self.table_name = 'post_versions' end def up create_table :post_versions do |t| t.references :post, null: false, foreign_key: true t.integer :version_no, null: false t.string :event_type, null: false t.string :title t.string :url, limit: 768, null: false t.string :thumbnail_base, limit: 2000 t.text :tags, null: false t.references :parent, foreign_key: { to_table: :posts } t.datetime :original_created_from t.datetime :original_created_before t.datetime :created_at, null: false t.references :created_by_user, foreign_key: { to_table: :users } t.index [:post_id, :version_no], unique: true t.check_constraint 'version_no > 0' t.check_constraint "event_type IN ('create', 'update', 'discard', 'restore')" end say_with_time 'Backfilling post_versions' do Post.find_in_batches(batch_size: 500) do |posts| post_ids = posts.map(&:id) tag_names_by_post_id = PostTag .joins('INNER JOIN tags ON tags.id = post_tags.tag_id') .joins('INNER JOIN tag_names ON tag_names.id = tags.tag_name_id') .where(post_id: post_ids) .where('post_tags.discarded_at IS NULL') .where('tags.discarded_at IS NULL') .where('tag_names.discarded_at IS NULL') .pluck('post_tags.post_id', 'tag_names.name') .each_with_object(Hash.new { |h, k| h[k] = [] }) do |(post_id, tag_name), h| h[post_id] << tag_name end rows = posts.map do |post| tags = tag_names_by_post_id[post.id].uniq.sort.join(' ') { post_id: post.id, version_no: 1, event_type: 'create', title: post.title, url: post.url, thumbnail_base: post.thumbnail_base, tags:, parent_id: post.parent_id, original_created_from: post.original_created_from, original_created_before: post.original_created_before, created_at: post.created_at, created_by_user_id: post.uploaded_user_id } end PostVersion.insert_all!(rows) if rows.present? end end end def down drop_table :post_versions end end