如何让ActiveRecord在Ruby on Rails中显示下一个id(last + 1)?

ran*_*its 42 activerecord ruby-on-rails

如果一个对象将被持久化到数据库,是否有一种紧凑的方式使用ActiveRecord来查询下一个要使用的id?在SQL中,像这样的查询看起来像:

SELECT max(id) + 1 FROM some_table;
Run Code Online (Sandbox Code Playgroud)

kim*_*een 89

这里稍微修改了Taryn East的版本:

Model.maximum(:id).next
Run Code Online (Sandbox Code Playgroud)

  • 如果没有行存在,则会出现异常(nil下一个未定义).我建议改进:`Model.maximum(:id).to_i.next` (18认同)
  • @ RustamA.Gasanov你的解决方案将产生错误的id,特别是如果你的id是字母数字(例如C10293029).在继续执行.next或返回默认值之前,假设您将获得nil并检查它更安全.我认为这比Taryn的答案更安全 (3认同)
  • 好的,但如果最后一条记录被销毁了怎么办?`User.maximum(:id).next`返回27,在'User.last.destroy`之后它26,但是现在 - 新记录有id 27.我不认为这是一种100%安全的方法来预测id (3认同)

sam*_*207 31

在接受无花果的回答时,我可能想把你的注意力集中在一件小事上.如果您在保存之前将下一个ID设置为特定记录,我认为这不是一个好主意.

因为在基于Web的系统中作为示例

  1. 你得到的最后一个id为10
  2. 您将下一个ID设置为11
  3. 在保存其他人保存记录的记录之前,现在最后一个id应该是12同样..

我不确定你想让最后一个id做我在想的事情,但如果是这样的话,那只是为了引起你的注意.


Les*_*ill 19

如果你的数据库是Postgres,你可以用这个得到下一个id(例如一个名为'users'的表):

ActiveRecord::Base.connection.execute("select last_value from users_id_seq").first["last_value"]
Run Code Online (Sandbox Code Playgroud)

与其他答案不同,此值不受删除记录的影响.

可能有一个mySQL等价物,但我没有一个设置确认.

如果已将数据导入postgresql数据库,则导入后的下一个id值很可能不会设置为大于您导入的最大值的下一个整数.因此,在尝试保存activerecord模型实例时会遇到问题.

在这种情况下,您需要手动设置下一个id值,如下所示:

ActiveRecord::Base.connection.execute("alter sequence users_id_seq restart with 54321;") #or whatever value you need
Run Code Online (Sandbox Code Playgroud)

  • MySQL等效项是“ ActiveRecord :: Base.connection.execute(“从information_schema.tables WHERE table_name ='<table_name>'” SELECT Auto_increment到).first.first(通过[this SO answer](https:// stackoverflow。 com / a / 1405500/4865822)) (2认同)

Tar*_*ast 12

比接受的答案稍微好一些:

YourModel.maximum(:id) + 1
Run Code Online (Sandbox Code Playgroud)

仍然倾向于竞争条件等,但至少它会记录跳过的ID并且比通过id对表格进行排序然后返回最后一个更有效.


gab*_*lal 6

这是一个老问题,但是如果您删除了最后一条记录,则其他答案都无效:

Model.last.id #=> 10
Model.last.destroy
Model.last.id #=> 9, so (Model.last.id + 1) would be 10... but...
Model.create  #=> 11, your next id was actually 11
Run Code Online (Sandbox Code Playgroud)

我使用以下方法解决了问题:

current_value = ActiveRecord::Base.connection.execute("SELECT currval('models_id_seq')").first['currval'].to_i
Model.last.id #=> 10
Model.last.destroy
Model.last.id #=> 9
current_value + 1 #=> 11
Run Code Online (Sandbox Code Playgroud)