J'ai créé une table dans mon Rails avec Rails commande de génération de migrations. Voici ce fichier de migration:
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
Ensuite, je voulais stocker la latitude et la longitude sous forme d'entiers alors j'ai essayé de lancer:
Rails generate migration changeColumnType
et le contenu de ce fichier sont:
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
Je m'attendais à ce que le type de colonne change, mais le râteau a été abandonné et le message d'erreur suivant est apparu. Je me demandais pourquoi cela n'a pas abouti? J'utilise postgresql dans mon application.
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)
REMARQUE: le tableau ne contient aucune donnée. Merci
Je cite le manuel environ ALTER TABLE
:
Une clause USING doit être fournie s'il n'y a pas de conversion implicite ou d'affectation de l'ancien vers le nouveau type.
Ce dont vous avez besoin c'est:
ALTER TABLE listes ALTER longitude TYPE entier UTILISATION longitude :: int; ALTER TABLE listes ALTER latitude TYPE entier UTILISATION de latitude :: int;
Ou plus court et plus rapide (pour les grandes tables) en une seule commande:
ALTER TABLE listings ALTER longitude TYPE integer USING longitude::int
,ALTER latitude TYPE integer USING latitude::int;
Cela fonctionne avec ou sans données tant que toutes les entrées sont convertibles en integer
.
Si vous avez défini un DEFAULT
pour la colonne, vous devrez peut-être le supprimer et le recréer pour le nouveau type.
Voici article de blog sur la façon de procéder avec ActiveRecord .
Ou suivez les conseils de @ mu dans le commentaire. Il connaît son Ruby. Je ne suis bon qu'avec PostgreSQL ici.
J'inclurais le SQL brut dans votre fichier de migration comme ci-dessous pour qu'il mette à jour 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
Je sais que c'est un peu moche, mais je préfère simplement supprimer la colonne et ajouter à nouveau avec le nouveau type:
def change
remove_column :mytable, :mycolumn
add_column :mytable, :mycolumn, :integer, default: 0
end
Ce qui suit est un plus Rails way
pour aborder le problème. Pour mon cas, j'avais deux colonnes dans ma table d'achats que j'avais besoin de convertir du type chaîne en flottant.
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
Cela a fait l'affaire pour moi.
la latitude et la longitude sont décimales
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