Get ID before save

Hi,

it’s possible, get value of ID before save the object?

I need ID concatenated with year for make new value of other column in table.

I try with before_save but in this point, before_save don’t know ID.

I try with after_save but in this point, the object was save, so i have to update object.

two transactions to make it.

I think this isn’t DRY.

How make better? make DRY?

Does have rails a possibility to get ID before save?

PS: sorry for my bad english, i’m learning :slight_smile:

Can you get away with making your other attribute a "virtual" one--not store it in the database at all? So for instance:

class KivianosThing < ActiveRecord::Base   def kivianos_virtual_column     id.to_s + year_attribute   end end

?

HTH,

-Roy

Kivanio Barbosa wrote:

Hi,

it's possible, get value of ID before save the object?

I need ID concatenated with year for make new value of other column in table.

I try with before_save but in this point, before_save don't know ID.

I try with after_save but in this point, the object was save, so i have to update object.

two transactions to make it.

I think this isn't DRY.

How make better? make DRY?

Does have rails a possibility to get ID before save?

PS: sorry for my bad english, i'm learning :slight_smile:

The ID doesn't get assigned until it gets saved on create, so there will never be an id before that happens. after_save or after_create is probably your best option.

Another question though is do you really need an extra column in the database? Can you dynamically create this value in your model? Such as...

def special_id_field     "foo_#{id}" end

@thing.special_id_field #=> "foo_42"

Hi,

it's possible, get value of ID before save the object?

It's not known until the save has happened (you can't know whether
someone else might insert something into the table which would affect
the autogenerated id).

Fred

Kivanio Barbosa wrote:

Hi,

it's possible, get value of ID before save the object?

Impossible before a save. You could, however, add 'another' id like pseudo_id and set that before hand with max_id + 1 or something -R

I'm no database expert but I think that if you go this route you have to ensure that during the time you get max_id, no other inserts are happening. So going this route can not guarantee that you'll 'always' get the desired result.

-Jason

Hi guys,

thanks answers.

I need the column because it is a key, a uniq number to control orders, users will use to select state of order in future. So, the key can't be a virtual attribute.

The max_id is a good ideia, but, i need lock table to get it and generate the key, then insert object in databse and unlock table. It's Similar to use after_save to get ID, then generate key and update objetct.

In two cases, i need two access to database to make it and in first case, i will need lock table. i prefer after_save in this case, i found out a loop in use it.

When i use after_save:

after_save :calc_number

def calc_number     carta = Carta.find self.id     numero = "#{self.id}/#{Time.now.year}"     carta.update_attribute(:numero, numero)   end

in this point "carta.update_attribute(:numero, numero)" was happen a loop, because update_attribute call Base.save and Base.save after update call after_save again, after_save call Base.save again until rails freeze in infinite loop.

In rails doc:

after_save() Is called after Base.save (regardless of whether it’s a create or update save).

I don't know if it is a bug, but it's impossible use update inside the after_save.

So, i choose use max_id and lock talbe to make it.

i like to eliminate one access to it, but i think it's imposible for rails because It depend of the database auto increment.

Thanks for help guys.

-Kivanio

you may be able to setup some mysql 'auto-increment' number or something and draw from it [at least there's something like that in postgres, not sure about mysql]. -R

Hey Kivanio, there are lots of ways to update a record within rails. Here are some ideas (and it depends on your code which will work)

#use save_without_validation.... doesn't bypass the before_/after_ callbacks, but it does move around the validation callbacks after_save :calc_number! def calc_number!   #this is wasteful!   # carta = Carta.find self.id   self[:numero] = "#{self.id}/#{Time.now.year}"   self.save_without_validation end

#you can use rail's update_all method, and just tie it down to that particular id def calc_number!   Carta.update_all(" numero= '#{self.id}/#{Time.now.year}.to_s(:db)'", "id = #{self.id}") end

#or you can use the rails private method that bypasses the callbacks. # it would be nice if this was public :wink: Patch perhaps? def calc_number!   self[:numero] = "#{self.id}/#{Time.now.year}"   self.send(:create_or_update_without_callbacks) end

Good luck Kivanio, Adam

Hi Adam,

great ideas

i solve my problem with after_create, it don’t init a loop and works fine.

#or you can use the rails private method that bypasses the callbacks.

it would be nice if this was public :wink: Patch perhaps?

def calc_number! self[:numero] = “#{self.id}/#{Time.now.year}” self.send(:create_or_update_without_callbacks) end

it’s amazing :smiley:

I like to use it.

thank you man.

ah, I forgot to mention that helper!

Well great, I'm glad it works! Adam