Есть ли документация для типов столбцов Rails?

181

Я ищу больше, чем простой список типов, который находится на этой странице :

: primary_key,: string,: text,: integer,: float,: decimal,: datetime,: timestamp,: time,: date,: binary,: boolean

Но есть ли документация, которая на самом деле определяет эти поля?

В частности:

  • Какая разница между :stringа :text?
  • Между :floatи :decimal?
  • Каковы отличительные черты :time, :timestampи :datetime?

Документированы ли нюансы этих типов где-нибудь?

РЕДАКТИРОВАТЬ: Точки реализации DB-платформы не имеют отношения к вопросу, который я пытаюсь задать. Если, скажем, :datetimeне имеет определенного предполагаемого значения в документации по Rails, то что делают разработчики db-адаптеров при выборе соответствующего типа столбца?

Грант Бирчмейер
источник
1
Как называются эти типы, извините за мой выбор слов, вещей ? Мол, это поля или атрибуты или что? Я искал другие вещи , кроме :stringи :textя не мог найти, кроме этого. Итак, я просто хотел узнать о будущем.
l1zZY
2
@ l1zZY, ​​вы можете искать термин «типы данных».
thatpaintingelephant

Ответы:

397

Руководство построено на личном опыте:

  • Строка :
    • Ограничено 255 символами (в зависимости от СУБД)
    • Используйте для коротких текстовых полей (имена, электронные письма и т. Д.)
  • Текст :
    • Неограниченная длина (в зависимости от СУБД)
    • Используйте для комментариев, сообщений в блоге и т. Д. Общее практическое правило: если оно записано с помощью textarea, используйте Text. Для ввода с использованием текстовых полей используйте строку.
  • Целое число :
    • Целые числа
  • Поплавок :
    • Десятичные числа хранятся с точностью до плавающей запятой
    • Точность фиксирована, что может быть проблематично для некоторых расчетов; как правило, не подходит для математических операций из-за неточного округления.
  • Десятичное число :
    • Десятичные числа хранятся с точностью, которая варьируется в зависимости от того, что необходимо для ваших расчетов; использовать их для математики, которая должна быть точной
    • В этом посте приведены примеры и подробное объяснение различий между числами и числами.
  • Логическое :
    • Используется для хранения атрибутов истина / ложь (т.е. вещи, которые имеют только два состояния, например, вкл / выкл)
  • Binary :
    • Используйте для хранения изображений, фильмов и других файлов в их исходном необработанном формате в виде фрагментов данных, называемых BLOB-объектами.
  • :основной ключ
    • Этот тип данных является заполнителем, который Rails преобразует в любой тип данных первичного ключа, который требуется для вашей базы данных (например, serial primary keyв postgreSQL). Его использование несколько сложное и не рекомендуется.
    • Вместо этого используйте ограничения модели и миграции (как validates_uniqueness_ofи add_indexс :unique => trueопцией) для имитации функциональности первичного ключа в одном из ваших собственных полей.
  • Дата :
    • Хранит только дату (год, месяц, день)
  • Время :
    • Хранит только время (часы, минуты, секунды)
  • DateTime :
    • Хранит дату и время
  • Отметка
    • Хранит дату и время
    • Примечание. Для целей Rails и Timestamp, и DateTime означают одно и то же (используйте любой тип для хранения даты и времени). Для описания TL; DR, почему оба существуют, прочитайте нижний абзац.

Это типы, о которых часто существует путаница; Надеюсь, это поможет. Я действительно не знаю, почему нет официальной документации об этом. Кроме того, я думаю, что эти адаптеры баз данных, на которые вы ссылались, были написаны теми же людьми, которые писали на Rails, поэтому им, вероятно, не требовалась документация, когда они писали адаптеры. Надеюсь это поможет!

Примечание: наличие обоих :DateTimeи :Timestamp, как я могу найти, включено в Rails главным образом для совместимости с системами баз данных. Например, TIMESTAMPтип данных MySQL хранится как метка времени Unix. Его действительный диапазон варьируется от 1970 до 2038 года, а время сохраняется как количество секунд, прошедших с последней эпохи , которое предположительно является стандартным, но на практике может различаться в зависимости от системы. Признавая, что относительное время не было подходящим для баз данных, MySQL позже представил DATETIMEтип данных, который хранит каждую цифру в году, месяце, дне, часе, минуте и секунде за счет увеличения размера. TIMESTAMP типа данных было сохранено для обратной совместимости. Другие системы баз данных претерпели аналогичные изменения. Rails признал, что существует множество стандартов, и предоставил интерфейсы для обоих. Тем не менее, Rails ActiveRecord по умолчанию , как :Timestampи :DateTimeк датам UTC хранятся в MySQL,DATETIME , так что это не имеет никакого функционального значения для Rails программистов. Они существуют для того, чтобы пользователи, которые хотятразграничить два можно сделать так. (Более подробное объяснение см. В этом ответе SO).

Агуазалес
источник
21
Это потрясающая рецензия, @aguazales. Кажется огромным упущением, что в документации по Rails нет ничего подобного.
Грант Бирчмайер,
Спасибо :) И я полностью согласен, ActiveRecord и его типы данных так важны для Rails, почему это не стандартная документация.
aguazales
2
Текст не всегда имеет неограниченную длину - в MySQL он ограничен до 16 КБ. Существуют типы баз данных MEDIUMTEXT и LONGTEXT, если вам нужно больше 16 КБ.
Хаегин
3
Это также хороший исходный тип данных Rails Migration - MySql - Postgresql - SQLite . Я знаю, что это специфично для базы данных, но знание фактической реализации все еще полезно при понимании типов базы данных rails.
конец
1
Я не могу быть уверен на 100%, но я думаю, что ресурс Нейта был размещен здесь .
aguazales
10

Из исходного кода главной ветки Rails я нашел:

абстрактный mysql_adapter

#activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

  NATIVE_DATABASE_TYPES = {
    primary_key: "bigint auto_increment PRIMARY KEY",
    string:      { name: "varchar", limit: 255 },
    text:        { name: "text", limit: 65535 },
    integer:     { name: "int", limit: 4 },
    float:       { name: "float" },
    decimal:     { name: "decimal" },
    datetime:    { name: "datetime" },
    timestamp:   { name: "timestamp" },
    time:        { name: "time" },
    date:        { name: "date" },
    binary:      { name: "blob", limit: 65535 },
    boolean:     { name: "tinyint", limit: 1 },
    json:        { name: "json" },
  }

  # Maps logical Rails types to MySQL-specific data types.
  def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil)
    sql = case type.to_s
    when 'integer'
      integer_to_sql(limit)
    when 'text'
      text_to_sql(limit)
    when 'blob'
      binary_to_sql(limit)
    when 'binary'
      if (0..0xfff) === limit
        "varbinary(#{limit})"
      else
        binary_to_sql(limit)
      end
    else
      super(type, limit, precision, scale)
    end

    sql << ' unsigned' if unsigned && type != :primary_key
    sql
  end    

# and integer ...

  def integer_to_sql(limit) # :nodoc:
    case limit
    when 1; 'tinyint'
    when 2; 'smallint'
    when 3; 'mediumint'
    when nil, 4; 'int'
    when 5..8; 'bigint'
    else raise(ActiveRecordError, "No integer type has byte size #{limit}")
    end
  end

 # and text ..

  def text_to_sql(limit) # :nodoc:
    case limit
    when 0..0xff;               'tinytext'
    when nil, 0x100..0xffff;    'text'
    when 0x10000..0xffffff;     'mediumtext'
    when 0x1000000..0xffffffff; 'longtext'
    else raise(ActiveRecordError, "No text type has byte length #{limit}")
    end
  end

# and binary ...

    def binary_to_sql(limit) # :nodoc:
      case limit
      when 0..0xff;               "tinyblob"
      when nil, 0x100..0xffff;    "blob"
      when 0x10000..0xffffff;     "mediumblob"
      when 0x1000000..0xffffffff; "longblob"
      else raise(ActiveRecordError, "No binary type has byte length #{limit}")
      end
    end

superв type_to_sqlметоде

#activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
  def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
    type = type.to_sym if type
    if native = native_database_types[type]
      column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup

      if type == :decimal # ignore limit, use precision and scale
        scale ||= native[:scale]

        if precision ||= native[:precision]
          if scale
            column_type_sql << "(#{precision},#{scale})"
          else
            column_type_sql << "(#{precision})"
          end
        elsif scale
          raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
        end

      elsif [:datetime, :time].include?(type) && precision ||= native[:precision]
        if (0..6) === precision
          column_type_sql << "(#{precision})"
        else
          raise(ActiveRecordError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6")
        end
      elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
        column_type_sql << "(#{limit})"
      end

      column_type_sql
    else
      type.to_s
    end
  end
Fangxing
источник