Get ID of Rails Model before saving…?

后端 未结 10 1225
鱼传尺愫
鱼传尺愫 2020-12-16 13:03

How do you get the id of a rails model before it is saved?

For example, if I create a new model instance, how can I get its ID before it is saved?

I know t

10条回答
  •  一整个雨季
    2020-12-16 13:17

    Most of the time when I needed an id can be grouped into a short list. When creating nested associations or connectin of the associations through. Let's assume we have: :user that have :pets through :user_pets association, where we will save their type.

    If we have a properly configured "has_many: through Association" we can just User.pets.create(name: "Rex") but this is too simplistic, as we want to creat :pet type in :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.
    

    You saw how this created all the ids for us? Let's move to something even more complex! Now we have an additional table :shampoo that exactly as :user_pet, belongs to a :pet and a :user We need to create it without knowing the id of the :user and :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!
    

    I tried to cover most common causes when you need element id, and how to overcome this. I hope it will be useful.

提交回复
热议问题