如何在Rails中更改记录的主ID?

B S*_*ven 19 activerecord ruby-on-rails ruby-on-rails-3

rails console
u = User.find(9)
u.id = 7 # There is no other record with id 7
u.save
=> true
User.all

id没有改变.

如何更改主ID?为什么会阻止此操作?

在Rails 3.0.7和PostgreSQL中工作.

编辑:由于有充分的理由不这样做,我会解释原因,希望这是一个很好的理由.

我们正在对暂存进行可用性测试,因此我希望它看起来像生产,以便让每个人都轻松.我不希望在可用性测试过程中产生混淆或错误,方法是在Staging上按一个顺序排序,在Production上按不同顺序排列.我只在Staging DB上更改了一个PK id.

不要在生产数据库上执行此操作!

Oli*_*ves 27

我不确定为什么它会阻止这种行为,但它肯定会阻止它.

您可以使用update_all方法为用户绕过此操作.

User.where(id: 7).update_all(id: 9)
Run Code Online (Sandbox Code Playgroud)

虽然如果可能的话,你真的应该避免这样做.

  • 这对我来说不起作用,rails docs中提到的语法效果更好`User.where(id:7).update_all id:9` (12认同)

tom*_*bak 10

对我来说工作:

User.find(9).update_column(:id, 7)
Run Code Online (Sandbox Code Playgroud)


Til*_*ilo 6

你能详细说明你的用例是什么吗?为什么要更改ID?你真的想用它做什么?

一般来说,这样做是个坏主意,Rails不会让你轻易做到这一点,因为它会破坏你的数据完整性!

这就是为什么: 当您在下面使用关系数据库(如PostgreSQL)时,您将在模型之间建立关系,这意味着您将使用模型的ID作为其他相关模型中的参考...这意味着如果您更改一个条目的ID,对该条目的所有引用都将过时并破坏您的数据库.

我强烈建议再次分析您的要求,并尝试找到另一种方法来完成您需要做的事情(不更改ID)

  • 谢谢你的提醒.我正在使我的Staging DB看起来像生产数据库.据我所知,所有引用用户ID 9的记录都将被孤立. (2认同)

Sye*_*lam 5

@Jason 指出了一个非常有效的观点。我完全同意他的观点。但是,您可能有自己的理由,我建议您重新考虑您要做什么。

回答你的问题:

默认情况下,ID 列受到批量分配保护,无法手动设置。但是,您可以通过定义一个方法来覆盖此行为:

def self.attributes_protected_by_default
  [] # ["id", ..other]
end
Run Code Online (Sandbox Code Playgroud)

这将允许您手动分配 id。


Lon*_*hus 5

另一种方法(尽管它不是纯 Rails)是创建一个新列,并用新 ID 填充它。

然后,使用数据库管理软件(不是 Rails),从 id 列中删除主键属性,将其删除,将最近添加的列重命名为“id”,并为其赋予主键属性。(如果您无法直接在数据库软件中执行此操作,请设置“唯一”、“自动增量”等属性)

您还可以将该列移到前面(MySQL 语法):

ALTER TABLE table_name MODIFY COLUMN id int(11) FIRST;
Run Code Online (Sandbox Code Playgroud)

但还有一件事我真的很想说。这个问题并不像我在其他地方看到的那么糟糕,但是各位:告诉人们这通常不是一个好主意固然很好,但这并不是问题的答案。除非您已经知道此人的用例,否则请不要说“不要这样做”。

在其他论坛上,我对人们说“你为什么要这样做?”感到非常沮丧。或“不要这样做”,然后不回答问题。他们并没有因为我已经知道这不是标准做法而给予我信任,并且他们认为我还不知道这不是一个普通的用例。

这个页面上的人并没有那么糟糕,我也不想挑剔他们。我只是劝告一下:请在讲课之前先检查一下自己的行为。有人提出了问题,虽然警告可能是个好主意,但可以安全地假设他们有想要答案的理由。

吐槽结束。