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

时间:2009-04-15 05:25:16

标签: ruby-on-rails ruby activerecord

所以我有两个模型,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并且记录进入以太。

9 个答案:

答案 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

来自the documentation

  

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

答案 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默认约定优于配置,对吧? - 专注于应用的重要部分,例如:用户界面和业务逻辑。