Ruby-on-rails 将 Rails 中的主键更改为字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/750413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Altering the primary key in Rails to be a string
提问by fr0man
So I've got two models, State and Acquisition. State has_many Acquisitions. I felt like an autoincrementing integer primary key for 51 records was rather silly. So I altered the model for the State to be the PK (State being the two letter abbreviation; I'm not storing the actual state name anywhere:
所以我有两个模型,State 和 Acquisition。状态 has_many 收购。我觉得 51 条记录的自动递增整数主键相当愚蠢。所以我将 State 的模型更改为 PK(State 是两个字母的缩写;我没有在任何地方存储实际的州名:
class State < ActiveRecord::Base
self.primary_key = "state"
has_many :acquisition_histories
end
The problem is when I created my Acquisition model, it created the foreign key column state_id as an integer. More specifically, the script/generated migration did:
问题是当我创建我的获取模型时,它将外键列 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
I'm assuming that t.references data type sets it to int. The problem is my create method on my Acquisition class is trying to put a state abbreviation into the state_id field on the table acquisitions (and yes, it's called state_id on the database, even though it says :state in the migration script). The method doesn't fail, but it does put a 0 in the state_id field and the records go into the ether.
我假设 t.references 数据类型将其设置为 int。问题是我的 Acquisition 类上的 create 方法试图将状态缩写放入表获取的 state_id 字段中(是的,它在数据库上称为 state_id,即使它在迁移脚本中说:state)。该方法不会失败,但它确实在 state_id 字段中放置了一个 0,并且记录进入了以太。
采纳答案by John Topley
Rails works best when you don't fight against the defaults. What harm does it do to have an integer primary key on your state table?
当您不与默认值作斗争时,Rails 效果最佳。在你的状态表上有一个整数主键有什么危害?
Unless you're stuck with a legacy schema that you have no control over, I'd advise you to stick to the Rails defaults—convention over configuration, right?—and concentrate on the important parts of your app, such as the UI and the business logic.
除非您坚持使用无法控制的旧架构,否则我建议您坚持使用 Rails 默认设置——约定优于配置,对吗?——并专注于应用程序的重要部分,例如 UI 和业务逻辑。
回答by mkirk
Though, I agree that this might be more trouble than it's worthconsidering the extra effort of working against the defaults elsewhere, just in case you actuallywant to do what you've asked:
不过,我同意这可能比考虑在其他地方针对默认值进行额外工作更麻烦,以防万一您真的想要执行您所要求的操作:
Create states migration:
创建状态迁移:
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
states model:
状态模型:
class State < ActiveRecord::Base
self.primary_key = :state
end
Note that before Rails 3.2, this was set_primary_key = :stateinstead of self.primary_key=see: http://guides.rubyonrails.org/3_2_release_notes.html#active-record-deprecations
请注意,在 Rails 3.2 之前,这是set_primary_key = :state而不是self.primary_key=看到:http: //guides.rubyonrails.org/3_2_release_notes.html#active-record-deprecations
回答by Wilhelm
if you find yourself here... leave as quickly as you can and go to: Using Rails, how can I set my primary key to not be an integer-typed column?
如果您发现自己在这里...尽快离开并转到: 使用 Rails,我如何将主键设置为不是整数类型的列?
回答by bloudermilk
In Rails 5.1 you can specify the type of the primary key at creation:
在 Rails 5.1 中,您可以在创建时指定主键的类型:
create_table :states, id: :string do |t|
# ...
end
From the documentation:
从文档:
A Symbol can be used to specify the type of the generated primary key column.
Symbol 可用于指定生成的主键列的类型。
回答by Bob Aman
I'm working on a project that uses UUIDs as primary keys, and honestly, I don't recommend it unless you're certain you absolutely need it. There are a ton of Rails plugins out there that will not work unmodified with a database that uses strings as primary keys.
我正在开发一个使用 UUID 作为主键的项目,老实说,除非您确定绝对需要它,否则我不推荐它。有大量的 Rails 插件在未经修改的情况下无法与使用字符串作为主键的数据库一起使用。
回答by Dennis
Note that mkirk's answercreates a faux primary key. This explains why ActiveRecord needs to be told what the primary key is. Inspecting the table reveals
请注意,mkirk 的回答创建了一个虚假的主键。这就解释了为什么需要告诉 ActiveRecord 主键是什么。检查表发现
Table "public.acquisitions"
Column | Type | Modifiers
--------+----------------------+-----------
state | character varying(2) |
name | character varying |
Indexes:
"index_acquisitions_on_state" UNIQUE, btree (state)
In practice this works as expected so nothing wrong there, but it could be nicer.
在实践中,这按预期工作,所以没有错,但它可能会更好。
We can keep the idcolumn and change its type to string*. The migration looks like
我们可以保留该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
Inspecting the table reveals that you have an actual primary key with all the goodies such as the unique key constraint (no unique index needed), not null constraint, and auto-incrementing key.
检查该表会发现您有一个实际的主键,其中包含所有优点,例如唯一键约束(不需要唯一索引)、非空约束和自动递增键。
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)
Andyou won't need to explicitly tell ActiveRecord what the primary is.
而且您不需要明确地告诉 ActiveRecord 主要是什么。
You'll want to consider setting a default id if none is provided.
如果没有提供,您将需要考虑设置默认 ID。
class MyModel < ActiveRecord::Base
before_create do
self.id = SecureRandom.uuid unless self.id
end
end
* Disclaimer: you should not change the default primary key unless you have good reason to
* 免责声明:除非您有充分的理由,否则不应更改默认主键
回答by August Lilleaas
You want to follow the Rails conventions. The extra primary key is not an issue in any way. Just use it.
您希望遵循 Rails 约定。额外的主键在任何情况下都不是问题。就用它。
回答by August Lilleaas
I had a bit of experience with string used as primary keys and it's a pain in the ***. Remember that by default if you want to pass an object with the default :controller/:action/:id pattern, the :id will be a string and this will probably lead to routing problems if some ids get weirdly formatted ;)
我对用作主键的字符串有一些经验,这在 *** 中很痛苦。请记住,默认情况下,如果您想使用默认的 :controller/:action/:id 模式传递对象,则 :id 将是一个字符串,如果某些 id 格式异常,这可能会导致路由问题;)
回答by todd
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

