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