是否有Rails列类型的文档?

Is there documentation for the Rails column types?

我要查找的不仅仅是本页上的简单类型列表:

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

但是,是否有真正定义这些字段的文档?

明确地:

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

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

编辑:DB平台实现的要点与我想问的问题无关。例如,如果:datetime在rails文档中没有定义的预期含义,那么在选择相应的列类型时,db适配器编写器会使用什么?


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

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

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

注:根据我的发现,:DateTime:Timestamp的存在主要是为了与数据库系统兼容,由rails提供的。例如,mysql的TIMESTAMP数据类型存储为unix时间戳。它的有效范围是从1970年到2038年,时间被存储为自上一个时代以来经过的秒数,这被认为是标准的,但在实践中,不同的系统可能有所不同。由于认识到在数据库中相对时间不是一件好事,MySQL后来引入了DATETIME数据类型,它以增加大小为代价存储年、月、日、小时、分钟和秒中的每个数字。为了向后兼容,保留了TIMESTAMP数据类型。其他数据库系统也经历了类似的演变。Rails认识到存在多个标准,并为两者提供了接口。但是,rails activerecord将:Timestamp:DateTime都默认为存储在mysql的DATETIME中的UTC日期,因此它对rails程序员没有任何功能上的区别。它们的存在是为了让想要区分两者的用户能够做到这一点。(有关更深入的解释,请参阅此答案)。


从Rails主分支源代码中,我发现:

抽象mysql_适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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