Modification d'un type de colonne en chaînes plus longues dans les rails

90

Lors de la première migration, j'ai déclaré sur une colonne contentune chaîne de caractères Activerecord a fait en sorte qu'elle soit une chaîne (255) selon l'annotation gem.

Après avoir poussé l'application vers heroku, qui utilise postgres, si j'entre dans le formulaire dans le contenu une chaîne plus longue que 255, j'obtiens l'erreur

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

Le problème est que j'ai besoin que ce contenu contienne une chaîne extrêmement longue peut-être (du texte libre, peut contenir des milliers de caractères)

  1. Quelle variable (la chaîne n'est-elle pas appropriée pour cela) pg accepterait-elle?
  2. Comment créer une migration pour remplacer le type de cette colonne

Merci

Nick Ginanto
la source

Réponses:

216

Vous devez utiliser textavec Rails si vous voulez une chaîne sans limite de longueur. Une migration comme celle-ci:

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

devrait régler les choses. Vous voudrez peut-être :null => falseou d'autres options à la fin de cela aussi.

Lorsque vous utilisez une stringcolonne sans limite explicite, Rails ajoutera un fichier implicite :limit => 255. Mais si vous utilisez text, vous obtiendrez le type de chaîne de longueur arbitraire pris en charge par la base de données. PostgreSQL vous permet d'utiliser une varcharcolonne sans longueur, mais la plupart des bases de données utilisent un type distinct pour cela et Rails ne sait pas varcharsans longueur. Vous devez utiliser textdans Rails pour obtenir une textcolonne dans PostgreSQL. Il n'y a pas de différence dans PostgreSQL entre une colonne de type textet une de type varchar(mais varchar(n) c'est différent). De plus, si vous déployez au-dessus de PostgreSQL, il n'y a aucune raison d'utiliser :string(AKA varchar) du tout, la base de données traite textetvarchar(n)la même chose en interne, sauf pour les contraintes de longueur supplémentaire pour varchar(n); vous ne devriez utiliser varchar(n)(AKA :string) que si vous avez une contrainte externe (comme un formulaire gouvernemental qui indique que le champ 432 du formulaire 897 / B aura 23 caractères) sur la taille de la colonne.

En passant, si vous utilisez une stringcolonne n'importe où, vous devez toujours spécifier le :limitpour vous rappeler qu'il existe une limite et vous devez avoir une validation dans le modèle pour vous assurer que la limite n'est pas dépassée. Si vous dépassez la limite, PostgreSQL se plaindra et lèvera une exception, MySQL tronquera tranquillement la chaîne ou se plaindra (selon la configuration du serveur), SQLite le laissera passer tel quel, et d'autres bases de données feront autre chose (se plaindront probablement) .

De plus, vous devriez également développer, tester et déployer sur la même base de données (qui sera généralement PostgreSQL chez Heroku), vous devriez même utiliser les mêmes versions du serveur de base de données. Il existe d'autres différences entre les bases de données (comme le comportement de GROUP BY) dont ActiveRecord ne vous isolera pas. Vous le faites peut-être déjà mais j'ai pensé que je le mentionnerais quand même.

mu est trop court
la source
13
Très bonne réponse. Une note: Rails ne prend actuellement pas en charge change_column avec la méthode de changement ( guides.rubyonrails.org/migrations.html#using-the-change-method ); si ma mémoire est bonne, vous créerez une migration irréversible si vous faites cela. Mieux vaut le faire à l'ancienne avec des méthodes haut / bas.
poetmountain
@BourbonJockey: Il est logique de changene pas pouvoir annuler automatiquement un changement de type et le Guide des migrations dit que "[la méthode de changement] Cette méthode est préférée pour écrire des migrations constructives (ajout de colonnes ou de tables)" et change_columnn'est pas t dans la liste que vous pointez donc je pense que vous avez raison. Je l'ai corrigé pour utiliser up/ down(avec une mise en garde sur le down), merci pour la tête haute.
mu est trop court le
4
Pour la future référence des autres lecteurs, la conversion de chaîne en texte dans Postgres sur Heroku de cette manière ne perdra PAS de données.
Marina Martin
2
@Dennis: Peut-être que "vous devriez développer, tester et déployer en utilisant la même base de données" serait plus précis. Le problème habituel est que les gens utilisent la configuration SQLite par défaut (ridicule) de Rails et que les choses s'effondrent lorsqu'ils se déploient par-dessus quelque chose d'autre. PostgreSQL est toujours l'option par défaut et la plus courante chez Heroku, non?
mu est trop court
3
Par ailleurs, l'hypothèse de Rails selon laquelle les champs de longueur non spécifiée devraient être de 255 caractères est étrange. Il n'est pas nécessaire dans PostgreSQL d'utiliser textuniquement pour obtenir une longueur illimitée; vous pouvez simplement utiliser sans contrainte varchar. Rails impose cette limite étrange, pas PostgreSQL.
Craig Ringer
8

Bien que la réponse acceptée soit excellente, je voulais ajouter ici une réponse qui, espérons-le, mieux traiter la question des affiches originales, partie 2, pour les non-experts comme moi.

  1. Comment créer une migration pour remplacer le type de cette colonne

génération d'une migration d'échafaudage

Vous pouvez générer une migration pour contenir votre modification en tapant dans votre console (remplacez simplement le tablepour le nom de vos tables et columnpour votre nom de colonne)

rails generate migration change_table_column

Cela générera une migration squelette à l'intérieur de votre dossier application / db / migrate / Rails. Cette migration est un espace réservé pour votre code de migration.

Par exemple, je souhaite créer une migration pour changer le type d'une colonne de stringà text, dans une table appelée TodoItems:

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

Lancer votre migration

Une fois que vous avez entré le code pour changer la colonne, exécutez simplement:

rake db:migrate

Pour appliquer votre migration. Si vous faites une erreur, vous pouvez toujours annuler la modification avec:

rake db:rollack

Méthodes haut et bas

Les références Upet Downméthodes de réponse acceptées , au lieu de la Changeméthode la plus récente . Depuis les rails 3.2 de l' ancien style , les méthodes Up and Down présentent quelques avantages par rapport à la nouvelle méthode Change. «Haut et bas» éviter ActiveRecord::IrreversibleMigration exception. Depuis la sortie de Rails 4, vous pouvez utiliser reversiblepour éviter cette erreur:

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

Profitez de Rails :)

Tony Cronin
la source