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

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

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

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

В частности:

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

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

EDIT: Точки реализации БД-платформы не имеют отношения к вопросу, который я пытаюсь задать. Если, скажем, :datetime не имеет определенного предполагаемого значения в документации Rails, то что do db-adapter-writer идут при выборе соответствующего типа столбца?

Ответ 1

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

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

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

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

Ответ 2

Из кода Rails master branch souce я нашел:

абстрактный 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 in 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