Alterar um tipo de coluna para strings mais longas em trilhos

90

Na primeira migração, eu declarei em uma coluna contentcomo string O Activerecord fez com que fosse string (255) de acordo com a gema de anotação.

Depois de enviar o aplicativo para heroku, que usa postgres, se eu inserir no formulário no conteúdo uma string maior que 255, recebo o erro

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

O problema é que preciso que esse conteúdo contenha uma string que seja extremamente longa, talvez (texto livre, pode ter milhares de caracteres)

  1. Que variável (a string não é apropriada para isso) a pg aceitaria?
  2. Como faço para criar uma migração para substituir o tipo dessa coluna

obrigado

Nick Ginanto
fonte

Respostas:

216

Você deve usar textcom Rails se quiser uma string sem limite de comprimento. Uma migração 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

deve resolver as coisas. Você pode querer :null => falseou algumas outras opções no final disso também.

Quando você usa uma stringcoluna sem um limite explícito, o Rails adicionará um implícito :limit => 255. Mas se você usar text, obterá qualquer tipo de string de comprimento arbitrário que o banco de dados suporta. PostgreSQL permite que você use uma varcharcoluna sem comprimento, mas a maioria dos bancos de dados usa um tipo separado para isso e o Rails não conhece varcharsem comprimento. Você tem que usar textno Rails para obter uma textcoluna no PostgreSQL. Não há diferença no PostgreSQL entre uma coluna do tipo texte outra do tipo varchar(mas varchar(n) é diferente). Além disso, se você estiver implantando em cima do PostgreSQL, não há razão para usar :string(AKA varchar), o banco de dados trata textevarchar(n)o mesmo internamente, exceto para as restrições de comprimento extra para varchar(n); você só deve usar varchar(n)(AKA :string) se tiver uma restrição externa (como um formulário do governo que diz que o campo 432 no formulário 897 / B terá 23 caracteres) no tamanho da coluna.

Como um aparte, se você estiver usando uma stringcoluna em qualquer lugar, você deve sempre especificar o :limitcomo um lembrete para si mesmo de que há um limite e você deve ter uma validação no modelo para garantir que o limite não seja excedido. Se você exceder o limite, o PostgreSQL reclamará e levantará uma exceção, o MySQL silenciosamente truncará a string ou reclamará (dependendo da configuração do servidor), o SQLite deixará passar como está e outros bancos de dados farão outra coisa (provavelmente reclamarão) .

Além disso, você também deve desenvolver, testar e implantar no mesmo banco de dados (que normalmente será PostgreSQL no Heroku), você deve até usar as mesmas versões do servidor de banco de dados. Existem outras diferenças entre os bancos de dados (como o comportamento de GROUP BY) das quais ActiveRecord não o isolará. Você pode já estar fazendo isso, mas pensei em mencioná-lo de qualquer maneira.

mu é muito curto
fonte
13
Ótima resposta. Uma observação: o Rails atualmente não oferece suporte a change_column com o método de alteração ( guias.rubyonrails.org/migrations.html#using-the-change-method ); se a memória não funcionar, você criará uma migração irreversível se fizer isso. Melhor fazer isso da maneira tradicional com métodos para cima / para baixo.
poetmountain 01 de
@BourbonJockey: Faz sentido que changenão seja capaz de reverter automaticamente uma mudança de tipo e o Guia de Migrações diz que "[o método de mudança] Este método é preferido para escrever migrações construtivas (adicionando colunas ou tabelas)" e change_columnisn ' t na lista que você aponta, então acho que você está certo. Consertei para usar up/ down(com uma ressalva sobre odown ), obrigado pelo .
mu é muito curto
4
Para referência futura de outros leitores, a conversão de string em texto no Postgres no Heroku desta maneira NÃO perderá dados.
Marina Martin
2
@Dennis: Talvez "você deva desenvolver, testar e implantar usando o mesmo banco de dados" seja mais preciso. O problema comum é que as pessoas usam a configuração (ridícula) do SQLite padrão do Rails e as coisas desmoronam quando são implantadas em cima de outra coisa. PostgreSQL ainda é a opção padrão e mais comum no Heroku, não?
mu é muito curto
3
Em uma nota lateral, a suposição do Rails de que campos de comprimento não especificado devem ter 255 caracteres é estranha. É não necessário no PostgreSQL para usar textapenas para obter comprimento ilimitado; você pode apenas usar sem restrições varchar. O Rails está impondo esse limite ímpar, não o PostgreSQL.
Craig Ringer
8

Embora a resposta aceita seja excelente, eu queria adicionar uma resposta aqui que, com sorte, lide melhor com a pergunta dos pôsteres originais, parte 2, para não especialistas como eu.

  1. Como faço para criar uma migração para substituir o tipo dessa coluna

gerando migração de andaime

Você pode gerar uma migração para manter sua alteração digitando em seu console (basta substituir o tablepelo nome das suas tabelas e columnpelo nome da coluna)

rails generate migration change_table_column

Isso irá gerar um esqueleto de migração dentro de sua aplicação Rails / db / migrate / pasta. Esta migração é um espaço reservado para seu código de migração.

Por exemplo, eu quero criar uma migração para alterar o tipo de uma coluna de string para text, em uma tabela chamada TodoItems:

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

Executando sua migração

Depois de inserir o código para alterar a coluna, execute:

rake db:migrate

Para aplicar sua migração. Se você cometer um erro, pode sempre reverter a alteração com:

rake db:rollack

Métodos para cima e para baixo

As referências Upe Downmétodos de resposta aceitos , em vez do Changemétodo mais recente . Desde o estilo antigo do rails 3.2 , os métodos Up e Down apresentaram algumas vantagens sobre o método Change mais recente. Evite 'para cima e para baixo' ActiveRecord::IrreversibleMigration exception. Desde o lançamento do Rails 4 você pode usar reversiblepara evitar este erro:

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

Aproveite o Rails :)

Tony Cronin
fonte