Module: ActiveRecord::Migration::Ext::ChangeTableMoveToEnd

Included in:
ActiveRecord::Migration
Defined in:
lib/active_record/migration/ext/change_table_move_to_end.rb

Defined Under Namespace

Modules: CommandRecorder

Instance Method Summary collapse

Instance Method Details

#change_table_move_to_end(table_name, &block) ⇒ Object

Provides a convenient way to reorder your columns, since you can’t use after: ‘other_field’ when using PostgreSQL (dba.stackexchange.com/questions/3276/how-can-i-specify-the-position-for-a-new-column-in-postgresql)

Adds a new copy of the given columns, copies data into the new columns, then removes the old columns, and renames the new columns to the original names.

Does not re-add indexes.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/active_record/migration/ext/change_table_move_to_end.rb', line 70

def change_table_move_to_end(table_name, &block)
  add_orig_columns = recorder_record do
    change_table table_name, &block
  end
  add_orig_columns.extend(CommandRecorder::Ext)
  # pp add_orig_columns.commands

  say_with_time_and_silence "Moving to end of #{table_name}: #{add_orig_columns.column_names.join(', ')}" do
    # Add a new copy of the given columns (with temporary names)
    add_new_columns = add_orig_columns.add_suffix('_copy').extend(CommandRecorder::Ext)
    # pp add_new_columns.commands
    add_new_columns.replay(self)

    # Copy data into the new columns
    column_names_to_temp_names = add_orig_columns.column_names.map do |name|
      [name, "#{name}_copy"]
    end
    reversible do |dir|
      dir.up do
        execute <<~END
          update #{table_name}
            set
              #{column_names_to_temp_names.map do |orig, temp|
                "#{temp} = #{orig}"
              end.join(",\n")}
            ;
        END
      end
      dir.down do
        execute <<~END
          update #{table_name}
            set
              #{column_names_to_temp_names.map do |orig, temp|
                "#{orig} = #{temp}"
              end.join(",\n")}
            ;
        END
      end
    end

    # Remove the old columns
    # pp add_orig_columns.inverse.commands
    add_orig_columns.inverse.replay(self)

    # Rename the new columns to the original names.
    add_new_columns.change_add_column_to_rename do |name|
      name.sub(/_copy$/, '')
    end.replay(self)
  end
end

#say_with_time_and_silence(message, &block) ⇒ Object



121
122
123
124
125
# File 'lib/active_record/migration/ext/change_table_move_to_end.rb', line 121

def say_with_time_and_silence(message, &block)
  say_with_time message do
    suppress_messages(&block)
  end
end