有关于 Rails 列类型的文档吗?

我要寻找的不仅仅是简单的类型列表 你可以在此网页找到:

: basic _ key,: string,: text,: int,: float,: decal,: datetime,: time戳,: time,: date,: binary,: boolean

但是是否有任何文档实际上 定义这些字段?

具体来说:

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

这些类型的细微差别是否有记录在案?

编辑: 比方说,如果 :datetime在 Rails 文档中没有定义的预期含义,那么 db 适配器编写器在选择相应的列类型时会怎么做?

76884 次浏览

根据个人经验制定的指导方针:

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

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

注意: 就我所知,为了与数据库系统兼容,Rails 包含了 :DateTime:Timestamp。例如,MySQL 的 TIMESTAMP数据类型存储为 unix 时间戳。它的有效时间范围从1970年到2038年,时间以自上一个 新纪元以来已经过去的秒数存储,这被认为是标准的,但实际上可能因系统而异。MySQL 后来引入了 DATETIME数据类型,它从“1000-01-0100:00:00:00”开始以秒(可选的小数秒为5.6.4)形式存储,代价是 尺寸增加。为了向后兼容,保留了 TIMESTAMP数据类型。其他数据库系统也经历了类似的演变。Rails 认识到存在多种标准,并为这两种标准提供了接口。但是,Rails ActiveRecord 将存储在 MySql 的 DATETIME中的 :Timestamp:DateTime默认为 UTC 日期,因此对于 Rails 程序员来说没有功能上的区别。这些存在使得 :Timestamp0的用户可以区分这两者。(有关更深入的解释,请参见 :Timestamp1 SO 答案)。

从 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

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