是否有 Rails 列类型的文档?

Posted

技术标签:

【中文标题】是否有 Rails 列类型的文档?【英文标题】:Is there documentation for the Rails column types? 【发布时间】:2012-08-07 00:15:53 【问题描述】:

我正在寻找的不仅仅是简单的类型列表that is found on this page:

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

但是否有任何文档真正定义这些字段?

具体来说:

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

这些类型的细微差别是否记录在任何地方?

编辑:DB 平台实现的要点与我要问的问题无关。 如果说,:datetime 在 Rails 文档中没有定义的预期含义,那么什么db-adapter-writers 在选择对应的列类型时会经过吗?

【问题讨论】:

那些类型的,原谅我选择的词,事物,叫什么?比如,它们是字段还是属性或什么。我正在寻找除:string:text 之外的其他事物,但我找不到除此之外的任何东西。所以,我只是想供将来参考。 @l1zZY,您可能正在寻找的术语是“数据类型”。 【参考方案1】:

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

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

这些是经常存在混淆的类型;我希望这有帮助。我真的不知道为什么没有关于这些的官方文档。另外,我想您提到的这些数据库适配器是由编写 Rails 的同一个人编写的,因此他们在编写适配器时可能不需要任何文档。希望这会有所帮助!

注意:据我所知,:DateTime:Timestamp 都包含在 Rails 中,主要是为了与数据库系统兼容。例如,mysqlTIMESTAMP 数据类型存储为 unix 时间戳。它的有效范围从 1970 年到 2038 年,时间存储为自上次 epoch 以来经过的秒数,这应该是标准的,但实际上可能因系统而异。 MySQL 后来引入了DATETIME 数据类型,它从“1000-01-01 00:00:00”开始存储为秒(自 5.6.4 起可选小数秒),代价是size increase。保留TIMESTAMP 数据类型是为了向后兼容。其他数据库系统也经历了类似的演变。 Rails 认识到存在多种标准,并为这两种标准提供了接口。但是,Rails ActiveRecord 将:Timestamp:DateTime 都默认为存储在MySql 的DATETIME 中的UTC 日期,因此它对Rails 程序员没有功能上的区别。这些存在以便希望区分两者的用户可以这样做。 (有关更深入的解释,请参阅this SO 答案)。

【讨论】:

这是一篇很棒的文章,@aguazales。 Rails 文档中没有这样的内容似乎是一个巨大的疏忽。 谢谢 :) 我完全同意,ActiveRecord 及其数据类型对 Rails 非常重要,我知道为什么这不是标准文档。 文本的长度并不总是无限的——在 MySQL 中它被限制在 16kb 左右。如果您需要超过 16kb,则有 MEDIUMTEXT 和 LONGTEXT 数据库类型。 这也是一个很好的来源Rails Migration Data Types – MySql – Postgresql – SQLite。我知道它是特定于数据库的,但在了解 Rails 数据库类型时了解实际实现仍然很有帮助。 我不能 100% 确定,但我认为 Nate 的资源已被转发 here。【参考方案2】:

从我找到的 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

【讨论】:

ActiveRecord::Base.connection.native_database_types

以上是关于是否有 Rails 列类型的文档?的主要内容,如果未能解决你的问题,请参考以下文章

如何在rails中有很多通过创建关系

你如何更改rails中的列数据类型?

Rails 回形针,多种不同类型(PDF、图像、文档...)

在 Rails 生成器模板中查找列/属性的类型?

Ruby on rails - 2 种用户类型

Rails“徽章”类型插件/教程?