Cambiar un tipo de columna a cadenas más largas en rieles

90

En la primera migración, declaré en una columna contentque era una cadena. Activerecord lo convirtió en una cadena (255) de acuerdo con anotar gema.

Después de enviar la aplicación a heroku, que usa postgres, si ingreso en el formulario en el contenido una cadena de más de 255, aparece el error

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

El problema es que necesito que el contenido contenga una cadena que quizás sea extremadamente larga (texto libre, podría tener miles de caracteres)

  1. ¿Qué variable (la cadena no es apropiada para esto) aceptaría pg?
  2. ¿Cómo creo una migración para reemplazar el tipo de esa columna?

Gracias

Nick Ginanto
fuente

Respuestas:

216

Debe usar textcon Rails si desea una cadena sin límite de longitud. Una migración como esta:

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

debería arreglar las cosas. Es posible que desee :null => falseo algunas otras opciones al final de eso también.

Cuando usa una stringcolumna sin un límite explícito, Rails agregará un implícito :limit => 255. Pero si lo usa text, obtendrá cualquier tipo de cadena de longitud arbitraria que admita la base de datos. PostgreSQL le permite usar una varcharcolumna sin una longitud, pero la mayoría de las bases de datos usan un tipo separado para eso y Rails no conoce varcharsin una longitud. Tienes que usar textRails para obtener una textcolumna en PostgreSQL. No hay diferencia en PostgreSQL entre una columna de tipo texty una de tipo varchar(pero varchar(n) es diferente). Además, si está implementando sobre PostgreSQL, no hay ninguna razón para usar :string(AKA varchar) en absoluto, la base de datos trata textyvarchar(n)lo mismo internamente excepto por las restricciones de longitud extra para varchar(n); solo debe usar varchar(n)(AKA :string) si tiene una restricción externa (como un formulario gubernamental que dice que el campo 432 en el formulario 897 / B tendrá 23 caracteres) en el tamaño de la columna.

Como acotación al margen, si está utilizando una stringcolumna en cualquier lugar, siempre debe especificar :limitcomo recordatorio para sí mismo que hay un límite y debe tener una validación en el modelo para asegurarse de que no se exceda el límite. Si excede el límite, PostgreSQL se quejará y generará una excepción, MySQL truncará silenciosamente la cadena o se quejará (dependiendo de la configuración del servidor), SQLite lo dejará pasar como está y otras bases de datos harán otra cosa (probablemente se quejen) .

Además, también debería estar desarrollando, probando e implementando sobre la misma base de datos (que normalmente será PostgreSQL en Heroku), incluso debería utilizar las mismas versiones del servidor de base de datos. Hay otras diferencias entre las bases de datos (como el comportamiento de GROUP BY) de las que ActiveRecord no lo aislará. Puede que ya estés haciendo esto, pero pensé en mencionarlo de todos modos.

mu es demasiado corto
fuente
13
Gran respuesta. Una nota: Rails actualmente no admite change_column con el método de cambio ( guides.rubyonrails.org/migrations.html#using-the-change-method ); si la memoria no funciona, creará una migración irreversible si lo hace. Es mejor hacerlo a la vieja usanza con métodos arriba / abajo.
poetmountain
@BourbonJockey: Tiene sentido que changeno pueda revertir automáticamente un cambio de tipo y la Guía de migraciones dice que "[el método de cambio] Este método es el preferido para escribir migraciones constructivas (agregar columnas o tablas)" y change_columnno t en la lista que señala, así que creo que tiene razón. Lo arreglé para usar up/ down(con una advertencia en el down), gracias por el aviso.
mu es demasiado corto
4
Para referencia futura de otros lectores, la conversión de cadena a texto en Postgres en Heroku de esta manera NO perderá datos.
Marina Martin
2
@Dennis: Quizás "debería desarrollar, probar e implementar utilizando la misma base de datos" sería más preciso. El problema habitual es que la gente usa la (ridícula) configuración predeterminada de SQLite de Rails y las cosas se desmoronan cuando se implementan encima de otra cosa. PostgreSQL sigue siendo la opción predeterminada y más común en Heroku, ¿no?
mu es demasiado corto
3
En una nota al margen, la suposición de Rails de que los campos de longitud no especificada deben tener 255 caracteres es extraña. En PostgreSQL no es necesario usarlo textsolo para obtener una longitud ilimitada; puede usar sin restricciones varchar. Rails está imponiendo este extraño límite, no PostgreSQL.
Craig Ringer
8

Si bien la respuesta aceptada es excelente, quería agregar una respuesta aquí que, con suerte, se ocupa mejor de la parte 2 de la pregunta sobre los carteles originales, para los no expertos como yo.

  1. ¿Cómo creo una migración para reemplazar el tipo de esa columna?

generando migración de andamios

Puede generar una migración para mantener su cambio escribiendo en su consola (solo reemplace el tablepor el nombre de su tabla y columnpor el nombre de su columna)

rails generate migration change_table_column

Esto generará una migración de esqueleto dentro de su aplicación Rails / db / migrate / carpeta. Esta migración es un marcador de posición para su código de migración.

Por ejemplo, quiero crear una migración para cambiar el tipo de columna de stringa text, en una tabla llamada TodoItems:

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

Ejecutando su migración

Una vez que haya ingresado el código para cambiar la columna, simplemente ejecute:

rake db:migrate

Para aplicar su migración. Si comete un error, siempre puede revertir el cambio con:

rake db:rollack

Métodos arriba y abajo

Las referencias Upy Downmétodos de respuesta aceptados , en lugar del Changemétodo más nuevo . Dado que los métodos de subida y bajada de estilo antiguo de rieles 3.2 presentaban algunas ventajas sobre el método de cambio más nuevo. Evitar 'Arriba y Abajo' . Desde el lanzamiento de Rails 4 , puede utilizar para evitar este error:ActiveRecord::IrreversibleMigration exceptionreversible

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

Disfruta de Rails :)

Tony Cronin
fuente