Подтвердить что ты не робот

Rails Migrations: попытался изменить тип столбца из строки в целое

Я создал таблицу в моем приложении rails с командой rails generate migrations. Вот файл миграции:

class CreateListings < ActiveRecord::Migration
  def change
    create_table :listings do |t|
      t.string :name
      t.string :telephone
      t.string :latitude
      t.string :longitude

      t.timestamps
    end
  end
end

Затем я хотел сохранить широту и долготу как целые числа, поэтому Я попытался запустить:

rails generate migration changeColumnType

и содержимое этого файла:

class ChangeColumnType < ActiveRecord::Migration
  def up
    #change latitude columntype from string to integertype
    change_column :listings, :latitude, :integer
    change_column :listings, :longitude, :integer
    #change longitude columntype from string to integer type
  end

  def down  
  end
end

Я ожидал, что тип столбца изменится, но грабли были прерваны и появилось следующее сообщение об ошибке. Мне было интересно, почему это не прошло? Я использую postgresql в своем приложении.

rake db:migrate
==  ChangeColumnType: migrating ===============================================
-- change_column(:listings, :latitude, :integer)
rake aborted!
An error has occurred, this and all later migrations canceled:

PG::Error: ERROR:  column "latitude" cannot be cast to type integer
: ALTER TABLE "listings" ALTER COLUMN "latitude" TYPE integer

Tasks: TOP => db:migrate
(See full trace by running task with --trace)

ПРИМЕЧАНИЕ. В таблице нет DATA. Благодаря

4b9b3361

Ответ 1

Я цитирую руководство about ALTER TABLE:

Предложение USING должно быть предоставлено, если нет неявного или присвоения от старого до нового типа.

Что вам нужно:

ALTER TABLE listings ALTER longitude TYPE integer USING longitude::int;
ALTER TABLE listings ALTER latitude  TYPE integer USING latitude::int;

Или короче и быстрее (для больших таблиц) в одной команде:

ALTER TABLE listings ALTER longitude TYPE integer USING longitude::int
                    ,ALTER latitude  TYPE integer USING latitude::int;

Этот работает с данными или без них, пока все записи конвертируются в integer.
Если вы определили DEFAULT для столбца, вам может потребоваться отбросить и воссоздать это для нового типа.

Вот статья в блоге о том, как это сделать с помощью ActiveRecord.
Или идите с комментарием @mu в комментарии. Он знает свой Рубин. Я хорошо разбираюсь в PostgreSQL здесь.

Ответ 2

Я бы включил необработанный SQL в ваш файл миграции, как показано ниже, чтобы он обновлял schema.rb.

class ChangeColumnType < ActiveRecord::Migration
  def up
    execute 'ALTER TABLE listings ALTER COLUMN latitude TYPE integer USING (latitude::integer)'
    execute 'ALTER TABLE listings ALTER COLUMN longitude TYPE integer USING (longitude::integer)'
  end

  def down
    execute 'ALTER TABLE listings ALTER COLUMN latitude TYPE text USING (latitude::text)'
    execute 'ALTER TABLE listings ALTER COLUMN longitude TYPE text USING (longitude::text)'
  end
end

Ответ 3

Я знаю это немного уродливо, но я предпочитаю просто удалить столбец и снова добавить новый тип:

 def change
     remove_column :mytable, :mycolumn
     add_column :mytable, :mycolumn, :integer, default: 0
 end

Ответ 4

Ниже приведено rails way, чтобы подойти к проблеме. Для моего случая у меня было два столбца в моей таблице покупок, которые мне нужно было преобразовать из строки типа в float.

def change
    change_column :purchases, :mc_gross, 'float USING CAST(mc_gross AS float)'
    change_column :purchases, :mc_fee, 'float USING CAST(mc_fee AS float)'
end

Это помогло мне.

Ответ 5

  • У вас есть существующие данные в этих столбцах?
  • Вы не должны использовать int для широты и долготы. Они должны быть в плавающих точках.

Ответ 6

широта и долгота десятичная

rails g scaffold client name:string email:string 'latitude:decimal{12,3}' 'longitude:decimal{12,3}' 

class CreateClients < ActiveRecord::Migration[5.0]
  def change
    create_table :clients do |t|
      t.string :name
      t.string :email
      t.decimal :latitude, precision: 12, scale: 3
      t.decimal :longitude, precision: 12, scale: 3

      t.timestamps
    end
  end
end