所以我有两个模型,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并且记录进入以太。
答案 0 :(得分:36)
尽管如此,我同意这可能是more trouble than it's worth考虑到在其他地方违反默认值的额外努力,以防你实际想要做你所问的事情:
创建状态迁移:
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://guides.rubyonrails.org/3_2_release_notes.html#active-record-deprecations
答案 1 :(得分:32)
如果你发现自己在这里......尽可能快地离开并前往: Using Rails, how can I set my primary key to not be an integer-typed column?
答案 2 :(得分:6)
我正在开发一个使用UUID作为主键的项目,老实说,除非你确定你绝对需要它,否则我不推荐它。有大量的Rails插件无法使用字符串作为主键的数据库进行修改。
答案 3 :(得分:4)
在Rails 5.1中,您可以在创建时指定主键的类型:
create_table :states, id: :string do |t|
# ...
end
符号可用于指定生成的主键列的类型。
答案 4 :(得分:3)
请注意,mkirk's answer会创建一个虚拟主键。这解释了为什么需要告诉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,您将考虑设置默认ID。
class MyModel < ActiveRecord::Base
before_create do
self.id = SecureRandom.uuid unless self.id
end
end
*免责声明:除非您有充分理由
,否则不应更改默认主键答案 5 :(得分:2)
您想要遵循Rails惯例。额外的主键不是任何问题。只需使用它。
答案 6 :(得分:1)
我有一些使用字符串作为主键的经验,这是***的痛苦。请记住,默认情况下,如果要使用默认值:controller /:action /:id模式传递对象,则:id将是一个字符串,如果某些ID格式错误,这可能会导致路由问题;)
答案 7 :(得分:1)
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
答案 8 :(得分:-23)
当您不对抗默认值时,Rails效果最佳。在状态表上有一个整数主键有什么危害?
除非您遇到无法控制的旧架构,否则我建议您坚持Rails默认约定优于配置,对吧? - 专注于应用的重要部分,例如:用户界面和业务逻辑。