2015-07-22 12 views
6

Ho una colonna status in una tabella che voglio essere un enum. Inizialmente ho creato quel campo come un intero, pensando che avrei usato la funzionalità enum di Rails integrata. Risulta che richiede almeno Rails 4.1, ma sto usando 4.0 e il processo di aggiornamento richiederà del tempo.Postgres: Default per colonna (stringa) non può essere eseguito automaticamente per digitare enum

Ma pensare a come funziona tutto questo, mi sono reso conto che posso avere sia un enum ActiveRecord o un enum Postgres, non entrambi. Ho pensato che a lungo termine avere un enum postgres più esplicito sarebbe stato il migliore. Così, ho scritto una migrazione per convertire la colonna status da un intero a un enum.

execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');" 
change_column :site_applications, :status, "status_options USING status::status_options" 

Ma, ottengo questo errore:

PG::CannotCoerce: ERROR: cannot cast type integer to status_options 
ALTER TABLE "site_applications" ALTER COLUMN "status" TYPE status_options USING status::status_options 

Tutto quello che ho visto finora nella mia perquisizioni mi dice che dovrebbe hanno lavorato, ma non è così. Ho pensato che forse il problema è che non posso passare da intero a enum. Così sia. La mia soluzione era prima convertire la colonna in una stringa e quindi provare a convertirlo in enum.

change_column :site_applications, :status, :string 
execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');" 
change_column :site_applications, :status, "status_options USING status::status_options" 

E che mi dà il seguente errore:

PG::DatatypeMismatch: ERROR: default for column "status" cannot be cast automatically to type status_options 
ALTER TABLE "site_applications" ALTER COLUMN "status" TYPE status_options USING status::status_options 

Questo mi ha portato a credere che questo abbia qualcosa a che fare con il valore di default, così ho provato a specificare il valore di default nella dichiarazione change_column:

Che modifica correttamente la colonna in una stringa con un valore predefinito di "in sospeso", ma change_column non riesce con lo stesso "valore predefinito per colonna" errore.

Mi rendo conto che potrei semplicemente rilasciare la colonna tutti insieme e quindi ricrearla esattamente come voglio, ma a questo punto è una questione di posteri. Perché diamine non posso convertire una colonna da intero o stringa in enum? Chiunque?

AGGIORNAMENTO CON accettato risposta

in base alla risposta di Gary laggiù, questa è la migrazione che ha funzionato.

def up 
    execute "ALTER TABLE site_applications ALTER status DROP DEFAULT;" 
    execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');" 
    change_column :site_applications, :status, "status_options USING status::status_options", default: "pending" 
end 

def down 
    change_column :site_applications, :status, :string, default: "pending" 
    execute "DROP TYPE status_options;" 
end 
+0

si può mostrare i risultati di un \ site_applications dt in PSQL. Perché il messaggio suona come se ci fosse un valore predefinito impostato sulla colonna. Potrebbe essere necessario rimuovere l'impostazione predefinita mentre si apportano le modifiche e quindi aggiungere di nuovo un valore predefinito del tipo appropriato in seguito. – Gary

+0

@Gary Penso che tu abbia assolutamente ragione, ma non posso ** per la vita di me ** capire quale tipo di predefinito impostare in modo che possa essere passato a un enum. Ma ho eseguito '\ dt schema.site_applications' e questo è ciò che è stato restituito:' schema | site_applications | tabella | eliduke' –

+0

scusa, avrebbe dovuto essere \ d invece di \ dt – Gary

risposta

9

è necessario rimuovere il valore predefinito dalla colonna prima del cambiamento come predefinito è impostata su un valore che è valido per il vecchio tipo di colonna, ma incompatibile con il nuovo tipo.

alter table schema.site_applications alter status drop default 

Quindi è possibile modificare il tipo di colonna. Infine, una volta applicato il nuovo tipo di colonna, è possibile aggiungere un nuovo valore predefinito alla tabella.

alter table schema.site_applications alter status set default 'pending'::status_options 
Problemi correlati