2012-04-27 10 views
24

rails generate migrationsコマンドを使用して自分のテーブルに自分のテーブルを作成しました。Rails Migrations:列のタイプを文字列から整数に変更しようとしました

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 

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 

そして私が実行しようとした整数として緯度と経度を格納するよう を望んでいた:ここでマイグレーションファイルということです

私は、列の種類が変更されることを期待していましたが、レーキが中止され、次のエラーメッセージが表示されました。なぜこれが進まないのだろうと思っていたのですか?私のアプリで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はありません。 おかげ

+0

は、あなたがその上にデータがないことを確認し、あなたが単に列を削除し、正しいタイプでそれらを再度追加することができますデータはありません場合は、ロールバック –

+3

を作る試みることができる10進数です。緯度/経度全体がかなり大きいので、実際にどのようなタイプの列が必要か考えてみてください。 –

答えて

23

私は手動about ALTER TABLEを引用:

新しいタイプの古いから暗黙または割り当て キャストが存在しない場合、USING句が提供されなければなりません。あなたが必要なもの

は次のとおりです。(大きなテーブル用)

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

たり短くし、より高速な1つのコマンドで:

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

データの有無にかかわらず、この作品限り、すべてのエントリはintegerに変換可能です。
カラムにDEFAULTを定義した場合は、新しいタイプの値を削除して再作成する必要があります。

ここにはblog article on how to do this with ActiveRecordです。
コメントに@ muのアドバイスを付けてください。彼は彼のルビーを知っている。私はここのPostgreSQLだけで良いです。

+4

ワンオフの場合、最も簡単なことは、SQLを 'connection.execute( '...')'にラップすることです。 –

+1

レール移動の解法については、こちらをご覧ください:http://stackoverflow.com/questions/10690289/rails-gmaps4rails-gem-on-postgres – cintrzyk

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

整数を使用するか、lat/longは、必要な解像度を事前に知っていれば、はるかに高速でより効率的なストレージになります。 PITAは動作しますが、すべてのアルゴリズムがその形式でネイティブに動作できる場合を除き、変換エラーが発生する可能性があります。私はあなたが何か違うことが必要であり、正当な理由があることを知っていない限り、ダブルまたはフロートがより安全であることに同意します。 –

+0

文字列として格納するのは何ですか? – banditKing

+0

ここにGoogleマップの説明と推奨事項があります:https://developers.google.com/maps/articles/phpsqlajax#createtable – Victor

21

私は、以下のようにマイグレーションファイルに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 
+0

ダウンALTERは、文字列タイプに一致するテキストの代わりにvarcharでなければなりません。 – Martin

17

私は、これは少し醜いけど、私はただの列を削除し、新しいタイプに再び追加することを好む:

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

マイグレーションchange_column:mytable、:mycolumn、:floatを実行しました。その後、いくつかのマイグレーションを実行し、githubにプッシュし、このエラーを得るためにのみ英雄にプッシュしました。私は上記のように新しい移行を実行しましたが、以前の移行のためにエラーは引き続き発生します。 remove_columnは元に戻せないので、今はロールバックできません。私はフューバルですか? – tbone

+0

前のコメントへの更新:「rails destroy migration migrate_name」とrake db:migrateを使用して以前の移行を削除しました。 – tbone

7

次の問題にアプローチする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 

それは私のためのトリックでした。

+0

これは私にとって素晴らしい仕事でした。ありがとうございました。 –

0

緯度と経度は

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 
関連する問題