Большую часть времени, когда мне нужен был идентификатор, можно сгруппировать в короткий список.При создании вложенных ассоциаций или подключении ассоциаций через.Давайте предположим, что у нас есть: :user
, которые имеют ассоциацию от :pets
до :user_pets
, где мы сохраним их тип.
Если у нас правильно настроено "has_many: through Association", мы можем просто 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.
Вы видели, как это создало все идентификаторы для нас?Давайте перейдем к чему-то еще более сложному!Теперь у нас есть дополнительная таблица :shampoo
, которая точно так же, как :user_pet
, принадлежит :pet
и :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!
Я пытался охватить наиболее распространенные причины, когда вам нужен идентификатор элемента, и как это преодолеть.Надеюсь это будет полезно.