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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2755622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:36:58  来源:igfitidea点击:

How do I get ActiveRecord to show the next id (last + 1) in Ruby on Rails?

ruby-on-railsactiverecord

提问by randombits

Is there a compact way with ActiveRecord to query for what id it's going to use next if an object was going to be persisted to the database? In SQL, a query like this would look something like:

如果对象要持久化到数据库,ActiveRecord 是否有一种紧凑的方式来查询它接下来要使用的 id?在 SQL 中,这样的查询类似于:

SELECT max(id) + 1 FROM some_table;

回答by kimerseen

Here is slightly modified Taryn East's version:

这是Taryn East稍微修改的版本:

Model.maximum(:id).next

回答by sameera207

While accepting fig's answerI might want to draw your attention to a small thing. If you are getting the next ID to set to a particular record before saving, I think its not a good idea.

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

because as an example in a web based system

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

  1. you get the last id as 10
  2. you set the next id as 11
  3. before you save the record someone else has saved the record, now the last id should be 12 likewise..
  1. 你得到最后一个 id 为 10
  2. 您将下一个 ID 设置为 11
  3. 在您保存记录之前,其他人已经保存了该记录,现在最后一个 id 也应该是 12。

I'm not sure you want the last id to do what I'm thinking here, But if so this is just to draw your attention.

我不确定您是否希望最后一个 id 执行我在这里的想法,但如果是这样,这只是为了引起您的注意。

回答by Les Nightingill

If your database is Postgres, you can get the next id with this (example for a table called 'users'):

如果您的数据库是 Postgres,您可以获得下一个 id(例如名为“users”的表):

ActiveRecord::Base.connection.execute("select last_value from users_id_seq").first["last_value"]

Unlike the other answers, this value is not affected by the deletion of records.

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

There's probably a mySQL equivalent, but I don't have one set up to confirm.

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

If you have imported data into your postgresql database, there's a good chance that the next id value after the import is not set to the next integer greater than the largest one you imported. So you will run into problems trying to save the activerecord model instances.

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

In this scenario, you will need to set the next id value manually like this:

在这种情况下,您需要像这样手动设置下一个 id 值:

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

回答by Taryn East

Slightly better than the accepted answer:

比接受的答案略好:

YourModel.maximum(:id) + 1

Still prone to race-conditions etc, but at least it will take note of skipped ids and is slightly more efficient than, say, ordering the table by id then returning the last.

仍然容易出现竞争条件等,但至少它会注意到跳过的 id,并且比按 id 排序表然后返回最后一个更有效。

回答by gabrielhilal

This is an old question, but none of the other answers work if you have deleted the last record:

这是一个老问题,但如果您删除了最后一条记录,其他答案都不起作用:

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

I solved the problem using the following approach:

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

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

回答by 0x4a6f4672

If no one else is using the table (otherwise you would have to use locking), you could get the autoincrement value from MySQL, the SQL command is

如果没有其他人正在使用该表(否则您将不得不使用锁定),您可以从 MySQL 获取自动增量值,SQL 命令是

SELECT auto_increment FROM information_schema.tables 
WHERE table_schema = 'db_name' AND table_name = 'table_name';

and the Rails command would be

而 Rails 命令将是

ActiveRecord::Base.connection.execute("SELECT auto_increment 
     FROM information_schema.tables 
     WHERE table_schema = 'db_name' AND table_name = 'table_name';").first[0]

回答by user566245

Get the largest id on the table

获取表上最大的id

YourModel.maximum(:id)

YourModel.maximum(:id)

This will run the following sql

这将运行以下sql

SELECT MAX("your_models"."id") AS max_id FROM "your_models"

SELECT MAX("your_models"."id") AS max_id FROM "your_models"

Convert the result to an integer by calling to_i. This is important as for an empty table the above max command will return nil. Fortunately nil.to_ireturns 0.

通过调用将结果转换为整数to_i。这对于空表很重要,上面的 max 命令将返回nil。还好nil.to_i回来了0

Now to get the next available id, just add 1 +1`

现在要获取下一个可用的 id,只需添加 1 +1`

The final result:

最终结果

YourModal.maximum(:id).to_i+1

回答by Herman verschooten

If you want to be sure no one else can take the 'new' index, you should lock the table. By using something like:

如果您想确保没有其他人可以使用“新”索引,您应该锁定表。通过使用类似的东西:

ActiveRecord::Base.connection.execute("LOCK TABLES table_name WRITE")

and

ActiveRecord::Base.connection.execute("UNLOCK TABLES")

But this is specific for each database engine.

但这是特定于每个数据库引擎的。

The only correct answer for a sequential id column is:

顺序 id 列的唯一正确答案是:

YourModel.maximum(:id)+1

If you sort your model in a default scope, last and first will depend on that order.

如果您在默认范围内对模型进行排序,则 last 和 first 将取决于该顺序。

回答by dynex

I don't think there's a generic answer to this since you may not want to assume one database over another. Oracle, for example, may assign id's by a sequence or, worse, by a trigger.

我不认为对此有一个通用的答案,因为您可能不想假设一个数据库优于另一个。例如,Oracle 可能会通过序列或更糟糕的触发器来分配 id。

As far as other databases are concerned, one may set them up with non sequential or random id allocation.

就其他数据库而言,可以使用非顺序或随机 id 分配来设置它们。

May I ask what the use case is? Why would you need to anticipate the next id? What does 'next' mean? Relative to when? What about race conditions (multiuser environments)?

请问用例是什么?为什么需要预测下一个 ID?“下一个”是什么意思?相对于什么时候?竞争条件(多用户环境)呢?

回答by ocodo

There seems to be need of a answer here that removes the race conditions, and addresses the actual problem of pre-providing unique identifiers.

这里似乎需要一个答案来消除竞争条件,并解决预先提供唯一标识符的实际问题。

To solve the problem you maintain a second model, which serves unique ID's for the primary model. This way you don't have any race condition.

为了解决这个问题,您维护了第二个模型,该模型为主要模型提供唯一 ID。这样你就没有任何竞争条件。

If you need to make these ID's secure you should hash them with SHA256 (or SHA512) and store the hash as an indexed column on identifier model when they are generated.

如果您需要确保这些 ID 的安全,您应该使用 SHA256(或 SHA512)散列它们,并在生成它们时将散列存储为标识符模型上的索引列。

They can then be associated and validated when used on the primary model. If you don't hash them you still associate them, to provide validation.

然后可以在主模型上使用它们时进行关联和验证。如果您不散列它们,您仍然将它们关联起来,以提供验证。

I'll post some example code a bit later.

稍后我会发布一些示例代码。