【问题标题】:How to use long id in Rails applications?如何在 Rails 应用程序中使用长 id?
【发布时间】:2010-11-07 04:05:42
【问题描述】:

如何更改 ActiveRecord 的 ID 的(默认)类型? int 不够长,我更喜欢 long。我很惊讶迁移没有 :long - 是否只使用一些小数?

【问题讨论】:

  • 注意,Rails 5 中的情况发生了巨大变化,包括默认为 bigint,因此如果您使用的是 Rails 5+,请对以下所有答案持保留态度。

标签: ruby-on-rails activerecord int long-integer bigint


【解决方案1】:

感谢http://moeffju.net/blog/using-bigint-columns-in-rails-migrations

class CreateDemo < ActiveRecord::Migration
  def self.up
    create_table :demo, :id => false do |t|
      t.integer :id, :limit => 8
    end
  end
end
  • 查看选项 :id =&gt; false 禁用自动创建 id 字段
  • t.integer :id, :limit =&gt; 8 行将生成一个 64 位整数字段

【讨论】:

  • 不幸的是,这不会将 id 列创建为主键等。
  • 是的。我用原始 SQL 做到了这一点。我已经阅读了 soruce,但我没有找到任何明智的选择 (3.0.7) 。真可惜。但是,嘿! 3.1.0 已经有一段时间了!祝你好运!
  • 我发现这个是因为我在 postgres 中寻找要设置为 bigint 的 any 字段。 :id 信息是一个奖励!
  • @EricWang 这是很久以前的事了,我现在不做 Ruby on Rails(甚至)。但是这个我经常使用,我不记得有任何与“经典”标识符相关的回归。
  • @Notinlist 问题是关于long id,而不仅仅是long,因此最好将该列声明为主键。
【解决方案2】:

要设置默认主键列类型,迁移文件不是乱七八糟的地方。

相反,只需将其粘贴在 config/environment.rb 的底部

ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"

您的所有表都应使用id 的预期列类型创建:

+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| id           | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment | 

在你完成了你打算做的事情之后......下一个问题可能是“如何使我的外键列具有相同的列类型?”因为将主键 people.id 设置为 bigint(20) unsigned 并将 person_id 设置为 int(11) 或其他任何内容都没有意义?

对于这些列,您可以参考其他建议,例如

t.column :author_id, 'BIGINT UNSIGNED'
t.integer :author_id, :limit => 8

更新:@Notinlist,要在任意表上使用任意列作为主键,您需要执行 create_table-change_column 舞蹈:

create_table(:users) do |t|
  # column definitions here..
end
change_column :users, :id, :float # or some other column type

例如如果我想要guid 而不是自增整数,

create_table(:users, :primary_key => 'guid') do |t|
  # column definitions here..
end
change_column :users, :guid, :string, :limit => 36

【讨论】:

  • 这是一种有用的方法,但是有什么方法可以使这个数据库独立于数据库,或者这只是为满足这种需求而付出的代价?
  • 如果我不想为我的所有表使用bigint,只是为了一些?
  • 看起来像:primary_key =&gt; 'guid' 然后更改为字符串将不起作用。如果我理解正确,根据定义,在迁移中对primary_key 的引用会创建一个自动递增字段,因此它不适用于字符串。请参阅 Rudd Zwolinski 的回答 here
  • 我会非常强烈建议不要先创建后更改,至少在 Rails 2.3.x 中是这样。如果您在运行此迁移后检查您的 db/schema.rb 文件,您会注意到它没有提及您的更改,因此任何从架构创建您的数据库(如测试)的人都不会具有相同的结构。
  • 对于mysql2适配器添加:if ActiveRecord::ConnectionAdapters.local_constant_names.include?("Mysql2Adapter") ActiveRecord::ConnectionAdapters::Mysql2Adapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY" end
【解决方案3】:

这很难通过迁移来设置主键,因为 Rails 会自动将其放入。

您以后可以像这样更改任何列:

change_column :foobars, :something_id, 'bigint'

您可以在初始迁移中将非主 ID 指定为自定义类型,如下所示:

create_table :tweets do |t|
  t.column :twitter_id, 'bigint'
  t.column :twitter_in_reply_to_status_id, 'bigint'
end

在我有“bigint”的地方,您可以放置​​您的数据库将用于您想要使用的数据库列类型的任何文本(例如,“unsigned long”)。

如果您需要将 id 列设为 bigint,最简单的方法是创建表,然后在同一迁移中使用 change_column 更改列。

使用 PostgreSQL 和 SQLite,架构更改是原子的,因此如果迁移失败,这不会让您的数据库处于奇怪的状态。使用 MySQL,您需要更加小心。

【讨论】:

  • 谢谢 - 使用 limit => 8 的“正常”列似乎可以解决问题,但对于 primary_key 这不起作用。对于 MySQL,我现在使用自定义 SQL 和执行。会更喜欢change_column,但这不会和初始创建有同样的问题,即主键列不支持:limit => 8?
  • 不,您可以将 change_column 与主键一起使用,如下所示:change_column :foobars, :id, "bigint"。因此,您将创建表,然后立即将 ID 列更改为 bigint。我仍然不认为将 :limit 与 int 列一起使用(无论如何使用 MySQL)因为 int 的最大大小是 2**31-1 无论如何。
  • 好的,我刚刚在 Rails 文档中查找了它,如果你这样做 t.column :foobar, :int, :limit => 8 你会得到一个 bigint。
【解决方案4】:

根据 Rails API 文档,可能的类型选项有:

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

可以使用:decimal,也可以根据需要直接执行命令:

class MyMigration
  def self.up
    execute "ALTER TABLE my_table ADD id LONG"
  end
end

正如 wappos 所指出的,您可以使用 :limit 等辅助选项来告诉 ActiveRecord 您希望该列有多大。因此,您将使用 :int 列和更大的 :limit。

【讨论】:

  • “正如 wappos 所指出的,您可以使用 :limit 之类的辅助选项来告诉 ActiveRecord 您希望该列有多大。因此您可以使用具有更大 :limit 的 :int 列。”如果他想要的大于整数,我认为这不会起作用。设置更大的限制不会改变最大尺寸。
  • 其实 :primary_key 没有 :limit 选项,所以这对主键列不起作用。
  • 我刚刚在 Rails 文档中查找了它,如果在整数列上使用 :limit => 8,您将得到一个 bigint。我没有意识到这一点。
【解决方案5】:

如果有人需要它来使用 PostgreSQL,请创建一个像这样的初始化程序:

# config/initializers/bigint_primary_keys.rb
ActiveRecord::Base.establish_connection
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:primary_key] = 'bigserial primary key'

由于 Rails 3.2(甚至更早的版本)中的延迟加载,在建立数据库连接之前不需要ActiveRecord::ConnectionAdapters::PostgreSQLAdapter

【讨论】:

  • 你不需要建立连接来做要求,只需要适当的适配器,例如对于 pg:需要 'active_record/connection_adapters/postgresql_adapter',mysql:需要 'active_record/connection_adapters/abstract_mysql_adapter',sqlite:需要 'active_record/connection_adapters/sqlite3_adapter',oracle:需要 'active_record/connection_adapters/oracle_enhanced_adapter'。
【解决方案6】:

rails4,你可以做到。

以下是在rails4 & postgres 中创建Dummy 模型的示例,

xxx_migrate_dummies.rb:

class CreateDummies < ActiveRecord::Migration
  def change
    create_table :dummies, :id => false do |t|
      t.column :id, :serial8, primary_key: true
      t.string :name, :limit => 50, null: false
      t.integer :size, null: false

      t.column :create_date, :timestamptz, null: false
    end
  end
end

做了什么:

  • 使用serial8作为id类型,为64位整数,定义为primary key
  • 它使用timestamptz 作为日期时间类型,其中包含时区信息,这对于跨越多个时区的应用程序很重要。

【讨论】:

    【解决方案7】:

    Rails 3,MySQL:

    t.column :foobar, :int, :limit => 8
    

    不给我一个 bigint,只给我一个 int。然而,

    t.column :twitter_id, 'bigint'
    

    工作正常。 (尽管它确实将我与 MySQL 联系在一起。)

    【讨论】:

    • 'bigint' 作为列类型也应该适用于 PostgreSQL。前几天我将它用于大小为 8 的 int 列。
    • 酷! MySQL 和 PostgreSQL 是唯一与我相关的。实际上,它们现在归我听说的同一个组织所有..
    • MySQL 现在归 Oracle 所有,但 PostgreSQL 并非如此,这可能意味着它会更加繁荣:)
    【解决方案8】:

    借鉴其他解决方案,针对最近对我有用的方法进行了调整。

    添加到config/initializers 中的文件。它声明了一个新的列类型(改编自 chookeat 的建议)。

    ActiveRecord::ConnectionAdapters::Mysql2Adapter::NATIVE_DATABASE_TYPES[:long_primary_key] = "BIGINT(20) DEFAULT NULL auto_increment PRIMARY KEY"

    使用长 id 的迁移是这样的:

        create_table :notification_logs, :id => false do |t|
    
          t.column :id, :long_primary_key
          # ...
        end
    

    【讨论】:

      【解决方案9】:

      我编写了一个名为 activerecord-native_db_types_override 的 gem,可让您更改将在迁移中使用的数据类型。

      在您的 Gemfile 中,添加:

      gem 'activerecord-native_db_types_override'
      

      然后在 config/environment.rb 中,要在 postgres 中使用长 id,添加:

      NativeDbTypesOverride.configure({
        postgres: {
          primary_key: { name: "bigserial primary key"}
        }
      })
      

      查看其README 了解最新信息。

      【讨论】:

        【解决方案10】:

        你可以这样做:

        class CreateUsers < ActiveRecord::Migration[5.0]
          def change
            create_table :users, id: :bigserial do |t|
              t.string :name
            end
          end
        end
        

        【讨论】:

          【解决方案11】:

          更正如何更改默认primary key列类型:

          代替:

          ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"
          

          你应该这样做:

          ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT(8) UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"
          

          否则您将无法在数据库层中添加foreign key 限制。

          【讨论】:

          • 您能否提供更多关于BIGINT(**8**)BIGINT 之间区别的详细信息,以及它如何影响MySQL 中的外键创建? (我尝试谷歌搜索和搜索 MySQL 文档,但特殊字符阻碍了搜索。)
          • 我怀疑 OP 只是为了强调这些星号。我编辑删除它们。顺便说一句,他也错了——MySQL中数字的精度值只会影响它们的显示宽度,在这种情况下不需要它们。
          • 注意,从 Rails ~5 开始,像这样覆盖 primary_key 不再有效。它被简单地忽略了。好消息是,从 Rails ~5 开始,主键的默认列类型是 bigint。但是,它不是unsigned。如果您希望 unsigned 成为默认值,请查看此 Github 问题并表示您的支持:github.com/rails/rails/issues/40967
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-24
          • 2012-10-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多