Modifica di un tipo di colonna in stringhe più lunghe nei binari


90

Alla prima migrazione, ho dichiarato che su una colonna contentera stringa Activerecord l'ha resa stringa (255) secondo annotate gem.

Dopo aver eseguito il push dell'app su heroku, che utilizza postgres, se nel form nel contenuto inserisco una stringa più lunga di 255 ottengo l'errore

PGError: ERROR: value too long for type character varying(255)

Il problema è che ho bisogno che il contenuto contenga una stringa che è estremamente lunga forse (testo libero, potrebbe essere migliaia di caratteri)

  1. Quale variabile (la stringa non è appropriata per questo) accetterebbe pg?
  2. Come creo una migrazione per sostituire il tipo di quella colonna

Grazie

Risposte:


216

Dovresti usare textcon Rails se vuoi una stringa senza limiti di lunghezza. Una migrazione come questa:

def up
  change_column :your_table, :your_column, :text
end
def down
  # This might cause trouble if you have strings longer
  # than 255 characters.
  change_column :your_table, :your_column, :string
end

dovrebbe sistemare le cose. Potresti volere :null => falseo anche altre opzioni alla fine.

Quando usi una stringcolonna senza un limite esplicito, Rails aggiungerà un file implicito :limit => 255. Ma se usi text, otterrai qualsiasi tipo di stringa di lunghezza arbitraria supportato dal database. PostgreSQL ti permette di usare una varcharcolonna senza una lunghezza, ma la maggior parte dei database usa un tipo separato per questo e Rails non conosce varcharsenza una lunghezza. Devi usare textin Rails per ottenere una textcolonna in PostgreSQL. Non c'è differenza in PostgreSQL tra una colonna di tipo texte una di tipo varchar(ma varchar(n) è diversa). Inoltre, se stai distribuendo su PostgreSQL, non c'è alcun motivo per usare :string(AKA varchar), il database tratta textevarchar(n)lo stesso internamente tranne che per i vincoli di lunghezza extra per varchar(n); dovresti usare varchar(n)(AKA :string) solo se hai un vincolo esterno (come un modulo governativo che dice che il campo 432 nel modulo 897 / B sarà lungo 23 caratteri) sulla dimensione della colonna.

Per inciso, se stai usando una stringcolonna ovunque, dovresti sempre specificare :limitcome promemoria a te stesso che c'è un limite e dovresti avere una convalida nel modello per assicurarti che il limite non venga superato. Se superi il limite, PostgreSQL si lamenterà e solleverà un'eccezione, MySQL troncerà silenziosamente la stringa o si lamenterà (a seconda della configurazione del server), SQLite la lascerà passare così com'è e altri database faranno qualcos'altro (probabilmente si lamenteranno) .

Inoltre, dovresti anche sviluppare, testare e distribuire sullo stesso database (che di solito sarà PostgreSQL su Heroku), dovresti persino usare le stesse versioni del server di database. Ci sono altre differenze tra i database (come il comportamento di GROUP BY) da cui ActiveRecord non ti isola. Potresti già farlo, ma ho pensato di menzionarlo comunque.


13
Bella risposta. Una nota: Rails attualmente non supporta change_column con il metodo change ( guides.rubyonrails.org/migrations.html#using-the-change-method ); se la memoria serve, creerai una migrazione irreversibile se lo fai. Meglio farlo alla vecchia maniera con metodi su / giù.
poetmountain

@BourbonJockey: ha senso che changenon sarebbe in grado di annullare automaticamente una modifica del tipo e la Guida alle migrazioni dice che "[il metodo di modifica] Questo metodo è preferito per scrivere migrazioni costruttive (aggiunta di colonne o tabelle)" e change_columnnon è ' t nell'elenco che indichi quindi penso che tu abbia ragione. L'ho risolto per utilizzare up/ down(con un avvertimento su down), grazie per l' avviso .
mu è troppo breve

4
Per riferimento futuro di altri lettori, la conversione da stringa a testo in Postgres su Heroku in questo modo NON perderà dati.
Marina Martin

2
@Dennis: Forse "dovresti sviluppare, testare e distribuire utilizzando lo stesso database" sarebbe più preciso. Il solito problema è che le persone usano la (ridicola) configurazione SQLite predefinita di Rails e le cose vanno in pezzi quando vengono distribuite sopra qualcos'altro. PostgreSQL è ancora l'opzione predefinita e più comune su Heroku, no?
mu è troppo breve

3
In una nota a margine, l'ipotesi di Rails che i campi di lunghezza non specificata dovrebbero essere 255 caratteri è strana. E ' non è necessaria in PostgreSQL da usare textsolo per avere lunghezza illimitata; puoi semplicemente usare unconstrained varchar. Rails sta imponendo questo limite strano, non PostgreSQL.
Craig Ringer

8

Sebbene la risposta accettata sia eccellente, volevo aggiungere una risposta qui che, si spera, si occupi meglio della domanda dei poster originali, parte 2, per i non esperti come me.

  1. Come creo una migrazione per sostituire il tipo di quella colonna

generazione di migrazione di scaffold

Puoi generare una migrazione per mantenere la tua modifica digitando nella tua console (sostituisci semplicemente il tablenome della tabella e il columnnome della colonna)

rails generate migration change_table_column

Questo genererà una migrazione scheletrica all'interno della tua cartella Rails application / db / migrate /. Questa migrazione è un segnaposto per il codice di migrazione.

Ad esempio, voglio creare una migrazione per cambiare il tipo di una colonna da stringa text, in una tabella chiamata TodoItems:

class ChangeTodoItemsDescription < ActiveRecord::Migration
  def change
     # enter code here
     change_column :todo_items, :description, :text
  end
end

Esecuzione della migrazione

Una volta inserito il codice per modificare la colonna, esegui:

rake db:migrate

Per applicare la tua migrazione. Se commetti un errore puoi sempre annullare la modifica con:

rake db:rollack

Metodi su e giù

I riferimenti Upe i Downmetodi di risposta accettati , invece del Changemetodo più recente . Dal momento che rails 3.2 i metodi Up e Down del vecchio stile presentavano alcuni vantaggi rispetto al metodo Change più recente. Evita "Su e Giù" ActiveRecord::IrreversibleMigration exception. Dal rilascio di Rails 4 puoi usare reversibleper evitare questo errore:

class ChangeProductsPrice < ActiveRecord::Migration
  def change
    reversible do |dir|
      change_table :products do |t|
        dir.up   { t.change :price, :string }
        dir.down { t.change :price, :integer }
      end
    end
  end
end

Divertiti con Rails :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.