Skip to content

Indexes lose uniqueness constraint when change_column is executed #1344

Open
@justindell

Description

@justindell

When running change_column in a migration, indexes are dropped first and then recreated. However, the recreated index doesn't have the same flags as the original one. Here is a bash script that sets up a new rails app, creates a unique column, and changes the length of the column. Notice that the index is no longer unique:

#!/bin/bash

SQL_SERVER_USERNAME="your_sql_server_username"
SQL_SERVER_PASSWORD="your_sql_server_password"

set -x

rails new change_column_bug
cd change_column_bug || exit 1

cat >"config/database.yml" <<EOF
development:
  adapter: sqlserver
  encoding: utf8
  username: $SQL_SERVER_USERNAME
  password: $SQL_SERVER_PASSWORD
  database: change_column_bug
  host: localhost
EOF

echo "gem 'activerecord-sqlserver-adapter'" >>Gemfile
bundle install

rails generate model Item name:string:uniq
rails db:reset
rails db:migrate

echo -e "\033[0;31m$(cat db/schema.rb | grep index)\033[0m"

rails generate migration LimitItemNameLengthTo100

SECOND_MIGRATION=$(ls db/migrate/*_limit_item_name_length_to100.rb)
cat >"$SECOND_MIGRATION" <<EOF
class LimitItemNameLengthTo100 < ActiveRecord::Migration[7.1]
  def change
    change_column :items, :name, :string, limit: 100
  end
end
EOF

rails db:migrate

echo -e "\033[0;31m$(cat db/schema.rb | grep index)\033[0m"

Here is the interesting part of the output if you don't wish to run the script:

++ cat db/schema.rb
++ grep index
+ echo -e '\033[0;31m    t.index ["name"], name: "index_items_on_name", unique: true\033[0m'
    t.index ["name"], name: "index_items_on_name", unique: true
+ rails generate migration LimitItemNameLengthTo100
      invoke  active_record
      create    db/migrate/20250613151945_limit_item_name_length_to100.rb
++ ls db/migrate/20250613151945_limit_item_name_length_to100.rb
+ SECOND_MIGRATION=db/migrate/20250613151945_limit_item_name_length_to100.rb
+ cat
+ rails db:migrate
== 20250613151945 LimitItemNameLengthTo100: migrating =========================
-- change_column(:items, :name, :string, {limit: 100})
   -> 0.2264s
== 20250613151945 LimitItemNameLengthTo100: migrated (0.2264s) ================

++ cat db/schema.rb
++ grep index
+ echo -e '\033[0;31m    t.index ["name"], name: "index_items_on_name"\033[0m'
    t.index ["name"], name: "index_items_on_name"

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions