Rails не распознает логические поля в устаревшей базе данных

Я написал приложение Rails, которое использует устаревшую базу данных MySQL. Одна таблица содержит это поле

CREATE TABLE `articles` (
  `active` tinyint(3) unsigned NOT NULL DEFAULT '0',
);

Я исправил схему с помощью

t.boolean "active",    :default => false

Но рельсы не распознают это поле как логическое.

[1] pry(main)> Article.new.active.class
=> Fixnum

Это создаст проблему при проверке, потому что у меня есть этот валидатор в моем классе.

class Article < ActiveRecord::Base
  validates_inclusion_of :active, :in => [true, false]
end

Когда я присваиваю логические значения этому полю, они преобразуются в FixNum, и проверка завершается с ошибкой с сообщением "1 is not included in the list"

Если я создаю новое приложение с той же моделью, сгенерированный код sql

CREATE TABLE `posts` (
  `active` tinyint(1) DEFAULT NULL,
)

И все работает нормально:

[1] pry(main)> Article.new.active.class
=> FalseClass

Есть ли способ сделать мой устаревший столбец распознаваемым как логический (возможно, без запуска миграции)?


person Fabio    schedule 26.07.2012    source источник


Ответы (2)


если не считать переопределяя методы в TrueClass и FalseClass, было бы приемлемо просто определить ваши собственные "устаревшие" логические значения для использования в ваших проверках, в следующих строках:

class Article < ActiveRecord::Base
  $legacy_false, $legacy_true = 0, 1
  validates_inclusion_of :active, :in => [$legacy_true, $legacy_false]
end
person wehal3001    schedule 26.07.2012
comment
Я бы также разрешил true и false, если они вообще не работают (т. е. попытка вставить true или false в этот столбец дает неверный результат) с устаревшим хранилищем. - person Romain; 26.07.2012

Хорошо, я обнаружил что для логического типа MySQL жестко запрограммировано на tinyint(1)

def simplified_type(field_type)
  return :boolean if adapter.emulate_booleans && field_type.downcase.index("tinyint(1)")

  case field_type
    when /enum/i, /set/i then :string
    when /year/i         then :integer
    when /bit/i          then :binary
  else
    super
  end
end

Я запустил эту миграцию в своей базе данных, чтобы заставить ее работать

class ChangeBooleanFields < ActiveRecord::Migration
  def up
    change_column :articles, :active, :boolean, :null => false, :default => false, :limit => nil
  end

  def down
    change_column :articles, :active, :integer, :null => false, :default => 0, :limit => 1
  end
end
person Fabio    schedule 26.07.2012