Изменение типа столбца на более длинные строки в рельсах

90

При первой миграции я объявил, что столбец contentявляется строкой, Activerecord сделал его строкой (255) в соответствии с гемом-аннотацией.

После того, как я нажимаю приложение на heroku, которое использует postgres, если я ввожу в форму в content строку длиннее 255, я получаю сообщение об ошибке

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

Проблема в том, что мне нужно, чтобы этот контент содержал строку, которая может быть очень длинной (свободный текст, может быть тысячи символов)

  1. Какая переменная (строка для этого не подходит) примет pg?
  2. Как мне создать миграцию для замены типа этого столбца

Благодарность

Ник Гинанто
источник

Ответы:

217

Вам следует использовать textс Rails, если вам нужна строка без ограничения длины. Такая миграция:

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

следует во всем разобраться. Возможно, вы захотите :null => falseили другие варианты в конце.

Когда вы используете stringстолбец без явного ограничения, Rails добавит неявный :limit => 255. Но если вы используете text, вы получите любой тип строки произвольной длины, который поддерживает база данных. PostgreSQL позволяет использовать varcharстолбец без длины, но в большинстве баз данных для этого используется отдельный тип, а Rails не знает об этом varcharбез длины. Вам нужно использовать textRails, чтобы получить textстолбец в PostgreSQL. Там нет никакой разницы в PostgreSQL между столбцом типа textи одного типа varchar(но varchar(n) это разные). Более того, если вы развертываете поверх PostgreSQL, нет никаких причин для использования :string(AKA varchar), база данных обрабатывает textиvarchar(n) внутренне также известное как то же самое, за исключением дополнительных ограничений длины varchar(n); вы должны использовать толькоvarchar(n) (AKA :string ) только в том случае, если у вас есть внешнее ограничение (например, правительственная форма, в которой указано, что поле 432 в форме 897 / B будет иметь длину 23 символа) на размер столбца.

Кроме того, если вы где-то используете stringстолбец, вы всегда должны указывать его :limitкак напоминание себе о том, что существует предел, и вы должны иметь проверку в модели, чтобы гарантировать, что предел не превышен. Если вы превысите лимит, PostgreSQL подаст жалобу и вызовет исключение, MySQL незаметно обрежет строку или пожалуется (в зависимости от конфигурации сервера), SQLite позволит передать ее как есть, а другие базы данных сделают что-то еще (вероятно, пожалуются) .

Кроме того, вы также должны разрабатывать, тестировать и развертывать одну и ту же базу данных (которая обычно будет PostgreSQL в Heroku), вы даже должны использовать те же версии сервера базы данных. Есть и другие различия между базами данных (например, поведение GROUP BY), от которых ActiveRecord вас не изолирует. Возможно, вы уже делаете это, но я все равно подумал об этом.


Обновление : новые версии ActiveRecord понимают varcharбез ограничений, поэтому, по крайней мере, с PostgreSQL вы можете сказать:

change_column :your_table, :your_column, :string, limit: nil

изменить varchar(n)столбец на varchar. textи varcharостаются тем же самым в отношении PostgreSQL, но некоторые конструкторы форм будут относиться к ним по-другому: varcharполучает, <input type="text">тогда как textполучает многострочность <textarea>.

mu слишком короткий
источник
13
Отличный ответ. Одно замечание: в настоящее время Rails не поддерживает change_column с методом изменения ( guides.rubyonrails.org/migrations.html#using-the-change-method ); если память не изменяет, вы создадите необратимую миграцию, если сделаете это. Лучше делать это по-старому, используя методы вверх / вниз.
Posemountain
@BourbonJockey: имеет смысл, changeчто нельзя автоматически отменить изменение типа, и в Руководстве по миграции действительно сказано, что «[метод изменения] Этот метод предпочтительнее для написания конструктивных миграций (добавление столбцов или таблиц)» и change_columnне t в списке, на который вы указываете, так что я думаю, что вы правы. Я исправил его для использования up/ down(с оговоркой down), спасибо за внимание.
mu слишком короткое
4
Для справок других читателей, преобразование строки в текст в Postgres на Heroku таким образом НЕ приведет к потере данных.
Марина Мартин
2
@Dennis: Возможно, «вам следует разрабатывать, тестировать и развертывать с использованием одной и той же базы данных» будет более точным. Обычная проблема заключается в том, что люди используют (нелепую) установку SQLite по умолчанию в Rails, и все разваливается, когда они развертываются поверх чего-то еще. PostgreSQL по-прежнему является наиболее распространенным вариантом по умолчанию в Heroku, не так ли?
mu слишком короткое
3
Кстати, предположение Rails о том, что поля неопределенной длины должны содержать 255 символов, является странным. В PostgreSQL нет необходимости использовать textтолько для получения неограниченной длины; вы можете просто использовать без ограничений varchar. Это странное ограничение накладывает Rails, а не PostgreSQL.
Craig Ringer
8

Хотя принятый ответ превосходен, я хотел добавить сюда ответ, который, надеюсь, лучше касается исходной части 2 вопроса плаката для неспециалистов, таких как я.

  1. Как мне создать миграцию для замены типа этого столбца

создание миграции каркаса

Вы можете сгенерировать миграцию, чтобы сохранить изменения, набрав в консоли (просто замените имя tableсвоей таблицы и имя columnстолбца)

rails generate migration change_table_column

Это приведет к миграции скелета внутри вашего приложения Rails / db / migrate / folder. Эта миграция является заполнителем вашего кода миграции.

Например, я хочу создать миграцию для изменения типа столбца с stringна textв таблице TodoItems:

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

Запуск миграции

После того, как вы ввели код для изменения столбца, просто запустите:

rake db:migrate

Чтобы применить вашу миграцию. Если вы допустили ошибку, вы всегда можете отменить изменение с помощью:

rake db:rollack

Методы вверх и вниз

Принятые ссылки на ответы Upи Downметоды вместо более нового Changeметода. Начиная с версии rails 3.2, методы Up и Down в старом стиле имели несколько преимуществ по сравнению с новым методом Change. Избегайте «вверх и вниз» ActiveRecord::IrreversibleMigration exception. Начиная с выпуска Rails 4 вы можете использовать, reversibleчтобы избежать этой ошибки:

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

Наслаждайтесь Rails :)

Тони Кронин
источник