如何在保存之前获取rails模型的id?
例如,如果我创建一个新的模型实例,如何在保存之前获取其ID?
我知道id是在onsave上根据数据库创建的,但是有解决方法吗?
答案 0 :(得分:8)
我也在寻找这个,我找到了答案:
假设模型名称是"模型"和表名是" models"
model.rb
before_save {
next_id=Model.connection.select_value("Select nextval('models_id_seq')")
}
这将输出您的记录将获取的值,如果它被保存
答案 1 :(得分:4)
通常当人们认为他们需要这样做时,他们实际上并不需要这样做。就像John说的那样,解释一下你想要做什么,有人可以建议一种方法来做到这一点,而不必提前知道id。
答案 2 :(得分:2)
使用自动递增整数主键的默认Rails约定,在保存之前无法获取模型的ID,因为当新行插入相关表时,它是由RDBMS生成的。
你实际上试图解决什么问题?
答案 3 :(得分:2)
这不是一个Rails问题,而是一个数据库问题。这个问题将出现在任何Web应用程序框架中,并且解决方案在所有地方都是相同的。您必须使用数据库事务。
基本流程将如下工作。
您将从这种方法中注意到的主要事项是,您回滚交易时ID会有差距。
答案 4 :(得分:1)
大多数时候,我需要一个id可以归为一个简短的列表。
在创建嵌套关联或连接关联时。
假设我们有:user
:pets
到:user_pets
关联,我们将保存其类型。
如果我们有一个正确配置的“has_many:通过协会”我们可以
User.pets.create(name: "Rex")
但这太简单了,因为我们想在:pet
中创建:user_pets
类型。
u = User.create(name: "Cesar")
u.id # => 1 # works fine
p = u.pets.create(name: 'Rex')
# => rails will create UserPets => {id: 1, user_id: 1, pet_id: 1} for us
# But now we have a problem, how do we find :user_pets of our :pet?
# remember we still need to update the :type, the ugly (wrong) way:
up = p.user_pets.first
up.type = 'dog'
up.save! # working but wrong
# Do you see the problems here? We could use an id
P = Pet.new( name: "Destroyer" )
p.id # will not work, as the pet not saved yet to receive an id
up = UserPet.new( user_id: U.id, pet_id: p.id )
# => UserPet {id: 2, user_id: 1, pet_id: nil} # as we expected there is no id.
# What solutions do we have? Use nested creation!
# Good
up = UserPet.new(user_id: u.id, type: "dog")
# even better
up = u.user_pets.new(type: "dog")
# it's just a shortcut for the code above,
# it will add :user_id for us, so let's just remember it.
# Now lets add another 'new' from our creatd 'user_pet'
p = up.pets.new(name: "Millan")
user.save!
# => UserPet: {id: 3, user_id: 1, pet_id: 2, type: 'dog'} # => Pet: {id: 2, name: "Sam"}
# everything is working! YEY!
# we can even better, than writing in the beginning "User.create",
# we can write "User.new" and save it with all the nested elements.
您是否看到了这为我们创造了所有的ID?让我们转向更复杂的事情吧!
现在我们有一个与:shampoo
完全相同的附加表:user_pet
,属于:pet
和:user
我们需要在不知道:user
和:pet
u = User.new('Mike')
up = u.user_pets.new(type: "cat")
p = up.pets.new(name: "Rowe")
# But what are we doing now?
# If we do:
s = u.shampoos.new(name: "Dirty Job")
# => Shampoo: {user_id: 2, pet_id: nil, name: "..."}
# We get "pet_id: nil", not what we want.
# Or if we do:
s = p.shampoos.new(name: "Schneewittchen")
# => Shampoo: {user_id: nil, pet_id: 3, name: "..."}
# We get "user_id: nil", in both cases we do not get what we want.
# So we need to get the id of not created record, again.
# For this we can just do as in the first example (order is not important)
s = u.shampoos.new(name: "Mission Impossible")
# => Shampoo: {id: 3, user_id: 2, pet_id: nil, name: "..."}
s.pet = p # this will give the missing id, to the shampoo on save.
# Finish with save of the object:
u.save! #=> Shampoo: {id: 3, user_id: 2, pet_id: 3, name: '...'} # => Pet: ...
# Done!
当你需要元素id时,我试图涵盖最常见的原因,以及如何克服这个问题。我希望它会有用。
答案 5 :(得分:0)
我不相信有任何变通办法,因为id实际上是由数据库本身生成的。在将对象保存到数据库之后,id才可用。
答案 6 :(得分:0)
在创建实例后立即考虑做你想做的事。
after_create do
print self.id
end
答案 7 :(得分:-1)
我在创建数据导入器时遇到了类似的情况。我正在创建一堆不同类型的记录,并在保存之前将它们关联起来。保存时,一些记录会抛出验证错误,因为它们有一个尚未保存的记录的validate_presence_。
如果您使用的是postgres,则活动记录会通过在数据库中保留名为models_id_seq(sales_id_seq for Sale等)的序列来增加它分配给Model的ID。您可以在此序列中获取下一个id,并使用以下函数递增它。
def next_model_id
ActiveRecord::Base.connection.execute("SELECT NEXTVAL('models_id_seq')").first["nextval"].to_i
end
但是,这种解决方案并不是一种好的做法,因为无法保证活动记录将来会以这种方式保留id序列。如果它在我的项目中只使用过一次,我只会使用它,为我节省了大量工作,并且在不应经常使用它的原因方面有很好的记录。
答案 8 :(得分:-1)
首先了解数据库的结构。
- Id使用序列萌发。
- 1的止痛药(在创建序列时指定)
- 最后进入数据库的值最高为
id
如果您想获取id
个要保存的记录,
然后您可以使用以下内容:
1. id = Model.last.id + 1
model = Model.new(id: id)
model.save
# But if data can be delete from that dataabse this will not work correctly.
2. id = Model.connection.select_value("Select nextval('models_id_seq')")
model = Model.new(id: id)
model.save
# Here in this case if you did not specified 'id' while creating new object, record will saved with next id.
e.g.
id
=> 2234
model = Model.new(id: id)
model.save
# Record will be created using 'id' as 2234
model = Model.new()
model.save
# Record will be created using next value of 'id' as 2235
希望这会对您有所帮助。
答案 9 :(得分:-7)
我知道这是一个古老的问题,但如果有人需要引用我的答案,也可以提出我的答案
<强>的usermodel 强>
class User < ActiveRecord::Base
before_create :set_default_value
def set_default_value
self.value ||= "#{User.last.id+1}"
end