Получить идентификатор модели Rails перед сохранением...?

Как вы получаете идентификатор модели рельсов до ее сохранения?

Например, если я создаю экземпляр новой модели, как я могу получить его ID до его сохранения?

Я знаю, что id создается onsave и в соответствии с базой данных, но есть ли способ обхода?

Ответы

Ответ 1

Обычно, когда люди думают, что им нужно это делать, им фактически не нужно это делать. Как говорит Джон, объясните, что вы пытаетесь сделать, и кто-то, вероятно, может предложить способ сделать это, не зная заранее идентификатор.

Ответ 2

Я тоже искал это, и я нашел ответ:

Предположим, что имя модели - "Модель", а имя таблицы - "модели"

model.rb

before_save {
    next_id=Model.connection.select_value("Select nextval('models_id_seq')")
}

Это выведет значение, которое ваша запись примет для id, если он будет сохранен

Ответ 3

Используя стандартное соглашение Rails для первичного ключа с автоматическим инкрементным целым, нет способа получить идентификатор модели до ее сохранения, поскольку она сгенерирована СУРБД, когда новая строка вставлена ​​в соответствующую таблицу.

Какую проблему вы пытаетесь решить?

Ответ 4

Это меньше вопрос с Rails и вопрос с базой данных. Это проблема, которая будет представлена ​​в любой среде веб-приложений, и решение будет одинаковым во всех местах. Вы должны использовать транзакцию базы данных.

Основной поток будет работать следующим образом.

  • Открыть транзакцию
  • Сохраните свою модель.
  • Использовать идентификатор, назначенный базой данных
  • Если окажется, что вы действительно не хотите сохранять эту модель в базе данных, откатите транзакцию.
  • Если окажется, что вы хотите сохранить модель в базе данных, совершите транзакцию.

Главное, что вы заметите из этого подхода, заключается в том, что в ваших идентификаторах будут пробелы, в которых вы откатили транзакцию.

Ответ 5

В большинстве случаев, когда мне нужен идентификатор, его можно сгруппировать в короткий список. При создании вложенных ассоциаций или connectin ассоциаций через. Предположим, что мы имеем: :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 just a shortcut for the code above, 
# it will add :user_id for us, so let 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.

Вы видели, как это создало для нас все идентификаторы? Позвольте перейти к чему-то еще более сложному! Теперь у нас есть дополнительная таблица :shampoo, которая точно равна :user_pet, принадлежит a :pet и a :user Нам нужно создать его, не зная id :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!

Я пытался охватить наиболее распространенные причины, когда вам нужен идентификатор элемента и как его преодолеть. Надеюсь, это будет полезно.

Ответ 6

Я не верю, что есть какие-то обходные пути, так как идентификатор фактически генерируется самой базой данных. Идентификатор должен быть недоступен до тех пор, пока объект не будет сохранен в базе данных.

Ответ 7

Подумайте о том, что вы хотите сразу после создания экземпляра.

after_create do
  print self.id
end

Ответ 8

Я просто столкнулся с аналогичной ситуацией при создании импортера данных. Я создавал кучу записей разных типов и связывал их перед сохранением. При сохранении некоторые из записей вызывали ошибки проверки, поскольку они имели validate_presence_ записи, которая еще не была сохранена.

Если вы используете postgres, активная запись увеличивает идентификатор, который он присваивает модели, сохраняя в базе данных последовательность с именем models_id_seq (sales_id_seq для продажи и т.д.). Вы можете получить следующий идентификатор в этой последовательности и увеличить его с помощью следующей функции.

def next_model_id
    ActiveRecord::Base.connection.execute("SELECT NEXTVAL('models_id_seq')").first["nextval"].to_i
end

Однако это решение не является хорошей практикой, поскольку нет никакой гарантии, что активная запись будет поддерживать идентификационные последовательности таким образом в будущем. Я бы использовал это только в том случае, если он использовался только один раз в моем проекте, и мне было очень много работы, и он был хорошо документирован с точки зрения того, почему его не следует часто использовать.

Ответ 9

Сначала поймите структуру базы данных.

  • Идентификатор создается с помощью последовательности.
  • увеличение на 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  

Надеюсь, это поможет вам.

Ответ 10

Я знаю, что это старый вопрос, но может также бросить мой ответ в случае, если кому-то понадобится его ссылка

UserModel

class User < ActiveRecord::Base
before_create :set_default_value

def set_default_value
   self.value ||= "#{User.last.id+1}"
end