【问题标题】:Should I delete the default "id" field when using a string primary key in Rails / Postgres?在 Rails / Postgres 中使用字符串主键时,我应该删除默认的“id”字段吗?
【发布时间】:2012-07-20 13:44:10
【问题描述】:

这是一个问题 I asked before 的构建(没有任何运气)。

我有一个使用字符串作为主键的模型:

class Employee < ActiveRecord::Base
   self.primary_key = "employment_id"
end 

此表还包含 Rails 默认的“id”字段,具有唯一性约束。

当我在本地添加新员工时,一切正常,Rails 会自动生成一个新的唯一 ID。

但是,当我在 Heroku Postgres 上运行它时,它似乎将 'id' 和 'employment_id' 视为同一个字段。我试图通过手动设置一个唯一的 id 来解决这个问题,但仍然会出现这种行为:

Employee.new do |s|

  max_id = Employee.maximum(:id)  
  puts max_id.to_s             # => 1803 

  s.employment_id = "fred_01"      
  s.id = max_id + 1 

  puts employment_id.to_s      # => 1804

end

我在本地运行 postgres 9.1.3(而 Heroku 在 9.1.4 上)。我在 Rails 3.2.3 上。

我的问题是:

  • 知道这里发生了什么吗?
  • 您认为我使用employment_id 作为主键是否正确?
  • 如果我删除“id”字段会有帮助吗?
  • 您还有其他最佳做法推荐吗?

感谢您的帮助!

德里克。

编辑:

按要求添加迁移文件:

class CreateEmployees < ActiveRecord::Migration
  def change
    create_table :employees do |t|
      t.string :employment_id, :unique => true
      etc...
    end
  end
end

编辑

没有人指出这一点,但我现在很清楚,真正的答案是“仅仅因为你可以,并不意味着你应该!”

【问题讨论】:

标签: ruby-on-rails postgresql activerecord heroku


【解决方案1】:

根据this的帖子,应该可以解决问题了:

class CreateEmployees < ActiveRecord::Migration
  def change
    create_table :employees, {:id => false} do |t|
      t.string :employment_id, :unique => true
      etc...
    end
  end
  execute "ALTER TABLE employees ADD PRIMARY KEY (employment_id);"
end

也在你的模型中:

class Employee < ActiveRecord::Base
  set_primary_key :employment_id
  ...
end

【讨论】:

  • 好东西。非常感谢!
  • 如果您使用的是 rails 3.2 或更高版本,则不推荐使用 set_primary_key 方法。 Rails 3.2 发行说明 - 第 8.1 节,它建议使用分配方法,例如“self.primary_key=:employment_id”
【解决方案2】:

Rails 4.2.0 和 Postgres 的更新,以防对任何人有所帮助...

create_table 选项中添加id: :string

class FooMigration < ActiveRecord::Migration
  def change
    create_table :foo, id: :string do |t|
      t.string :name, null: false
      t.timestamps null: false
    end
  end
end

rake db:迁移

== 20150225043441 FooMigration: migrating ===========================
-- create_table(:foo, {:id=>:string})    -> 0.0031s
== 20150225043441 FooMigration: migrated (0.0032s) ==================

rails db(和 \d foo)

psql (9.3.6)
Type "help" for help.

bar_development=# \d foo
                  Table "public.foo"
   Column   |            Type             | Modifiers 
------------+-----------------------------+-----------
 id         | character varying           | not null
 name       | character varying           | not null
 created_at | timestamp without time zone | not null
 updated_at | timestamp without time zone | not null
Indexes:
    "foo_pkey" PRIMARY KEY, btree (id)

我最终得到一个带有主键索引的“非空”字符串列。

使用id 以外的列名会更复杂。

编辑(2015 年 2 月 26 日):rails 在生成 schema.rb 文件时似乎存在错误。它不会记录自定义主键状态,您需要进入并对其进行编辑以将id: :string 选项添加到create_table 调用中。

即。

create_table "foo", id: :string, force: :cascade do |t|
  t.string   "name",       null: false
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

糟糕的部分:每次进行迁移时,该更改都会撤消。您必须密切关注文件内容(或编写测试:))。

该错误已在 PR 18228 中修复,并于 2015 年 1 月 3 日合并到 rails:master。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-17
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多