ruby-on-rails 有关于Rails列类型的文档吗?

a1o7rhls  于 2022-12-24  发布在  Ruby
关注(0)|答案(2)|浏览(149)

我正在寻找比这个页面上找到的简单类型列表更多的内容:
:主键,:字符串,:文本,:整数,:浮点型,:十进制,:日期时间,:时间戳,:时间,:日期,:二进制,:布尔型
但是,是否有任何文档实际上 * 定义 * 了这些字段?
具体而言:

  • :string:text有什么区别?
  • :float:decimal之间?
  • :time:timestamp:datetime的区别特征是什么?

这些类型的细微差别是否在任何地方记录在案?
编辑:**DB平台实现的要点与我试图提出的问题无关。**如果:datetime在Rails文档中没有定义的预期含义,那么db-adapter-writer在选择相应的列类型时会遵循什么?

jhdbpxl9

jhdbpxl91#

根据个人经验制定的指南:

      • 字符串**:
  • 限制为255个字符(取决于DBMS)
  • 用于短文本字段(姓名、电子邮件等)
      • 文本**:
  • 不限长度(取决于DBMS)
  • 用于评论、博客文章等。一般经验法则:如果它是通过文本区域获取的,使用文本。对于使用文本域的输入,使用字符串。
      • 整数**:
  • 整数
      • 浮动**:
  • 以浮点精度存储的十进制数
  • 精度是固定的,这对于某些计算可能是有问题的;通常由于不精确的舍入而不利于数学运算。
      • 小数**:
  • 存储的十进制数,其精度根据计算所需的精度而变化;我用这些来做需要精确的数学运算
  • 请参阅this post中的示例以及对浮点数和小数点之间差异的深入解释。
      • 布尔值**:
  • 用于存储真/假属性(即只有两种状态的事物,如开/关)
      • 二进制**:
  • 用于以原始格式将图像、影片和其他文件存储在称为"blob"的数据块中
    • :主键*
  • 这个数据类型是一个占位符,Rails会将其转换为数据库所需的任何主键数据类型(例如PostgreSQL中的serial primary key)。它的使用有些复杂,不推荐使用。
  • 使用模型和迁移约束(如带有:unique => true选项的validates_uniqueness_ofadd_index)来模拟您自己的某个字段上的主键功能。
      • 日期**:
  • 仅存储日期(年、月、日)
      • 时间**:
  • 仅存储时间(小时、分钟、秒)
      • 日期时间**:
  • 存储日期和时间
      • 时间戳**
  • 存储日期和时间
  • 注意:对于Rails来说,Timestamp和DateTime的含义是一样的(使用任一类型都可以存储日期和时间)。DR描述两者存在的原因,阅读底部段落。

这些都是经常存在混淆的类型。我真的不知道为什么没有关于这些的官方文档。另外,我想你提到的这些数据库适配器是由编写Rails的同一个人编写的,所以他们在编写适配器时可能不需要任何文档。
注:据我所知,:DateTime:Timestamp的存在主要是为了与数据库系统兼容,例如,MySQL的TIMESTAMP数据类型存储为unix时间戳,其有效范围从1970到2038,时间存储为自上一个纪元以来经过的秒数,这应该是标准的,但在实践中,不同的系统会有所不同。MySQL后来引入了DATETIME数据类型,它从"1000 - 01 - 01 00:00:00"开始以秒为单位存储(从5.6.4开始,可选的小数秒),代价是增加了数据大小。TIMESTAMP数据类型被保留用于向后兼容。其他数据库系统也经历了类似的演变。Rails认识到存在多种标准,并为两者提供了接口。然而,Rails ActiveRecord默认:Timestamp:DateTime为存储在MySql的DATETIME中的UTC日期,所以它对Rails程序员没有功能上的差异。这些数据类型的存在是为了让希望区分两者的用户能够这样做。(更深入的解释,请参见this SO答案)。

lmvvr0a8

lmvvr0a82#

从Rails master分支源代码中我发现:
abstract 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

type_to_sql方法中super

#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

相关问题