将Rails中的主键更改为字符串

所以我有两个模型,State和Acquisition。 State has_many收购。 我觉得51个记录的自动增量整数主键是相当愚蠢的。 所以我将State的模型改为PK(State是两个字母的缩写;我没有在任何地方存储实际的州名:

class State < ActiveRecord::Base self.primary_key = "state" has_many :acquisition_histories end 

问题是当我创建我的Acquisition模型时,它创建了外键列state_id作为整数。 更具体地说,脚本/生成的迁移确实:

 class CreateAcquisitions < ActiveRecord::Migration def self.up create_table :acquisitions do |t| t.date :date t.string :category t.text :notes t.references :state t.timestamps end end end 

我假设t.references数据类型将其设置为int。 问题是我的Acquisition类上的create方法试图将状态缩写放入表获取的state_id字段中(是的,它在数据库上称为state_id,即使它表示:迁移脚本中的状态)。 该方法不会失败,但它确实在state_id字段中放置了一个0并且记录进入以太。

当你不打击默认值时,Rails最有效。 在状态表上有一个整数主键有什么危害?

除非您遇到无法控制的旧架构,否则我建议您坚持使用Rails默认约定优于配置,对吧? – 专注于应用的重要部分,例如UI和业务逻辑。

虽然,我同意这可能比考虑在其他地方违反默认值的额外努力更值得考虑,以防你真的想要做你所问的事情:

创建状态迁移:

 class CreateStatesTable < ActiveRecord::Migration def change create_table :states, id: false do |t| t.string :state, limit: 2 t.string :name t.index :state, unique: true end end end 

国家模型:

 class State < ActiveRecord::Base self.primary_key = :state end 

请注意,在Rails 3.2之前,这是set_primary_key = :state而不是self.primary_key=请参阅: http : self.primary_key=

如果你发现自己在这里……尽快离开并转到: 使用Rails,如何将主键设置为不是整数类型的列?

我正在开发一个使用UUID作为主键的项目,老实说,除非你确定你绝对需要它,否则我不推荐它。 有大量的Rails插件无法使用字符串作为主键的数据库进行修改。

请注意, mkirk的答案创建了一个虚拟主键 。 这解释了为什么需要告诉ActiveRecord主键是什么。 检查表显示

  Table "public.acquisitions" Column | Type | Modifiers --------+----------------------+----------- state | character varying(2) | name | character varying | Indexes: "index_acquisitions_on_state" UNIQUE, btree (state) 

在实践中,这按预期工作,所以没有错,但它可能更好。


我们可以保留id列并将其类型更改为string *。 迁移看起来像

 class CreateAcquisitionsTable < ActiveRecord::Migration def change create_table :acquisitions do |t| t.string :name end change_column :acquisitions, :id, :string, limit: 2 end end 

检查表显示您有一个实际的主键,包含所有好处,例如唯一键约束(不需要唯一索引),非空约束和自动递增键。

  Table "public.acquisitions" Column | Type | Modifiers --------+----------------------+--------------------------------------------------- id | character varying(2) | not null default nextval('acquisitions_id_seq'::regclass) name | character varying | Indexes: "acquisitions_pkey" PRIMARY KEY, btree (id) 

而且您不需要明确告诉ActiveRecord主要内容是什么。

如果没有提供,您将需要考虑设置默认ID。

 class MyModel < ActiveRecord::Base before_create do self.id = SecureRandom.uuid unless self.id end end 

*免责声明:除非您有充分理由,否则不应更改默认主键

在Rails 5.1中,您可以在创建时指定主键的类型:

 create_table :states, id: :string do |t| # ... end 

从文档 :

符号可用于指定生成的主键列的类型。

您想要遵循Rails约定。 额外的主键不是任何问题。 只是使用它。

我有一些使用字符串作为主键的经验,这是***的痛苦。 请记住,默认情况下,如果要使用默认值:controller /:action /:id模式传递对象,则:id将是一个字符串,如果某些ID格式化,这可能会导致路由问题;)

 class CreateAcquisitions < ActiveRecord::Migration def self.up create_table :acquisitions, :id => false do |t| t.date :date t.string :category t.text :notes t.references :state t.timestamps end end end