web-dev-qa-db-ja.com

Rails Migrations:列のタイプを文字列から整数に変更しようとしました

Rails app with 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)

注:テーブルにはデータがありません。ありがとう

30
banditKing

私はマニュアルを引用します についてALTER TABLE

古いタイプから新しいタイプへの暗黙的または代入キャストがない場合は、USING句を指定する必要があります。

必要なものは:

 ALTER TABLEリストALTER経度TYPE整数 Longing :: intを使用する; 
 ALTER TABLEリストALTER緯度TYPE整数 緯度を使用して::整数; 

または、1つのコマンドで(大きなテーブルの場合)より短く、より速く:

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

これは、すべてのエントリがintegerに変換可能である限り、データの有無に関係なく機能します
列にDEFAULTを定義している場合は、それをドロップして、新しいタイプ用に再作成する必要がある場合があります。

これが ActiveRecordでこれを行う方法に関するブログ記事 です。
またはコメントに@muのアドバイスを添えてください。彼は自分のルビーを知っています。私はここでのPostgreSQLだけが得意です。

25

以下のようにraw 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
22
neverbendeasy

これは少し見づらいですが、列を削除して新しいタイプで再度追加することを好みます。

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

以下はもっとRails way問題に取り組みます。私の場合、購入表に2つの列があり、文字列型から浮動小数点型に変換する必要がありました。

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

それは私にとってはトリックでした。

11
Joseph N.
  1. これらの列に既存のデータはありますか?
  2. 緯度と経度にはintを使用しないでください。代わりに、浮動小数点にする必要があります。
2
Victor

緯度と経度は10進数です

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
0
gilcierweb