Ändern eines Spaltentyps in längere Zeichenfolgen in Schienen

90

Bei der ersten Migration habe ich eine Spalte contentals Zeichenfolge deklariert. Activerecord hat sie gemäß annotate gem als Zeichenfolge (255) festgelegt.

Nachdem ich die App an Heroku gesendet habe, das Postgres verwendet, erhalte ich den Fehler, wenn ich in das Formular eine Zeichenfolge eingebe, die länger als 255 ist

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

Das Problem ist, dass dieser Inhalt eine Zeichenfolge enthalten muss, die möglicherweise extrem lang ist (Freitext, kann Tausende von Zeichen enthalten).

  1. Welche Variable (ist der String dafür nicht geeignet) würde pg akzeptieren?
  2. Wie erstelle ich eine Migration, um den Typ dieser Spalte zu ersetzen?

Vielen Dank

Nick Ginanto
quelle

Antworten:

215

Sie sollten textmit Rails verwenden, wenn Sie eine Zeichenfolge ohne Längenbeschränkung möchten. Eine Migration wie diese:

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

sollte die Dinge regeln. Vielleicht möchten Sie auch :null => falseeinige andere Optionen am Ende.

Wenn Sie eine stringSpalte ohne explizite Begrenzung verwenden, fügt Rails eine implizite Spalte hinzu :limit => 255. Wenn Sie jedoch verwenden text, erhalten Sie den von der Datenbank unterstützten Zeichenfolgentyp beliebiger Länge. Mit PostgreSQL können Sie eine varcharSpalte ohne Länge verwenden, aber die meisten Datenbanken verwenden dafür einen separaten Typ, und Rails weiß nichts varcharohne Länge. Sie müssen textin Rails verwenden, um eine textSpalte in PostgreSQL zu erhalten. Es gibt keinen Unterschied in PostgreSQL zwischen einer Spalte vom Typ textund einem vom Typ varchar(aber varchar(n) ist anders). Wenn Sie zusätzlich zu PostgreSQL bereitstellen, gibt es keinen Grund für die Verwendung :string(AKA varchar). Die Datenbank behandelt textundvarchar(n)das gleiche intern mit Ausnahme der zusätzlichen Längenbeschränkungen für varchar(n); Sie sollten varchar(n)(AKA :string) nur verwenden, wenn Sie eine externe Einschränkung (z. B. ein Regierungsformular, das besagt, dass das Feld 432 in Formular 897 / B 23 Zeichen lang ist) für die Spaltengröße haben.

Wenn Sie eine stringSpalte irgendwo verwenden, sollten Sie dies immer :limitals Erinnerung an sich selbst angeben , dass es ein Limit gibt, und Sie sollten eine Validierung im Modell haben, um sicherzustellen, dass das Limit nicht überschritten wird. Wenn Sie das Limit überschreiten, beschwert sich PostgreSQL und löst eine Ausnahme aus, MySQL schneidet die Zeichenfolge leise ab oder beschwert sich (abhängig von der Serverkonfiguration), SQLite lässt sie unverändert passieren und andere Datenbanken tun etwas anderes (wahrscheinlich beschweren) .

Außerdem sollten Sie auf derselben Datenbank (normalerweise PostgreSQL bei Heroku) entwickeln, testen und bereitstellen. Sie sollten sogar dieselben Versionen des Datenbankservers verwenden. Es gibt andere Unterschiede zwischen Datenbanken (z. B. das Verhalten von GROUP BY), von denen ActiveRecord Sie nicht isoliert. Sie machen das vielleicht schon, aber ich dachte, ich würde es trotzdem erwähnen.

mu ist zu kurz
quelle
13
Gute Antwort. Ein Hinweis: Rails unterstützt derzeit change_column mit der Änderungsmethode nicht ( Guides.rubyonrails.org/migrations.html#using-the-change-method ). Wenn Speicherplatz zur Verfügung steht, erstellen Sie in diesem Fall eine irreversible Migration. Besser auf die alte Art und Weise mit Up / Down-Methoden.
Poetmountain
@ BourbonJockey: Es ist sinnvoll, changeeine Typänderung nicht automatisch rückgängig machen zu können, und im Migrationshandbuch heißt es: "[die Änderungsmethode] Diese Methode wird zum Schreiben konstruktiver Migrationen (Hinzufügen von Spalten oder Tabellen) bevorzugt" und change_columnisn ' t in der Liste, auf die Sie zeigen, also denke ich, dass Sie Recht haben. Ich habe es repariert , um up/ zu verwenden down(mit einer Einschränkung auf dem down), danke für die Heads-Ups.
Mu ist zu kurz
4
Wenn andere Leser in Postgres on Heroku auf diese Weise von Zeichenfolge zu Text konvertieren, gehen KEINE Daten verloren.
Marina Martin
2
@Dennis: Vielleicht wäre "Sie sollten mit derselben Datenbank entwickeln, testen und bereitstellen" genauer. Das übliche Problem ist, dass Benutzer das (lächerliche) Rails-Standard-SQLite-Setup verwenden und die Dinge auseinanderfallen, wenn sie über etwas anderem bereitgestellt werden. PostgreSQL ist immer noch die Standard- und häufigste Option bei Heroku, nicht wahr?
Mu ist zu kurz
3
Nebenbei bemerkt ist Rails Annahme, dass Felder mit nicht spezifizierter Länge 255 Zeichen haben sollten, seltsam. In PostgreSQL ist es nicht erforderlich, textnur eine unbegrenzte Länge zu verwenden. Sie können nur uneingeschränkt verwenden varchar. Rails legt diese ungerade Grenze fest, nicht PostgreSQL.
Craig Ringer
8

Obwohl die akzeptierte Antwort ausgezeichnet ist, wollte ich hier eine Antwort hinzufügen, die hoffentlich besser mit der ursprünglichen Posterfrage Teil 2 für Nicht-Experten wie mich umgeht.

  1. Wie erstelle ich eine Migration, um den Typ dieser Spalte zu ersetzen?

Gerüstmigration erzeugen

Sie können eine Migration generieren, um Ihre Änderung zu speichern, indem Sie in Ihre Konsole eingeben (ersetzen tableSie einfach den Namen für Ihre Tabellen und columnfür Ihren Spaltennamen).

rails generate migration change_table_column

Dadurch wird eine Skelettmigration in Ihrer Rails-Anwendung / db / migrate / folder generiert. Diese Migration ist ein Platzhalter für Ihren Migrationscode.

Zum Beispiel möchte ich eine Migration erstellen, um den Typ einer Spalte von stringnach textin einer Tabelle namens TodoItems zu ändern:

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

Führen Sie Ihre Migration aus

Nachdem Sie den Code zum Ändern der Spalte eingegeben haben, führen Sie einfach Folgendes aus:

rake db:migrate

So wenden Sie Ihre Migration an Wenn Sie einen Fehler machen, können Sie die Änderung jederzeit zurücksetzen mit:

rake db:rollack

Auf- und Ab-Methoden

Die akzeptierten Antwortreferenzen Upund Down-methoden anstelle der neueren ChangeMethode. Da Rails 3.2 Up- und Down-Methoden im alten Stil einige Vorteile gegenüber der neueren Change-Methode bieten. 'Auf und Ab' vermeiden ActiveRecord::IrreversibleMigration exception. Seit der Veröffentlichung von Rails 4 können Sie reversiblediesen Fehler vermeiden:

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

Viel Spaß mit Rails :)

Tony Cronin
quelle