id last inserted record?

Hi, I'm trying to find a way in RoR to retrieve the id of the last record I just saved to a database.

I know there is something like LAST_INSERT_ID on MySQL, but I don't seem to find how to use it - if it is possible in RoR.

What is the right way to get that ID in RoR? IS there a way to retrieve it?

Help greatly appriciated.

Hi, I'm trying to find a way in RoR to retrieve the id of the last record I just saved to a database.

(...)

What is the right way to get that ID in RoR? IS there a way to retrieve it?

If you used ActiveRecord to insert, you can just read the 'id' attribute of the last inserted object. Say you do:

elephant = Elephant.create :name => 'Fred'

Then elephant.id is your newly inserted id.

mymodel.save! puts "Last ID is #{mymodel.id}"

Is that helpful? If not, perhaps:

last_id = MyModel.maximum('id')

Anything else is likely database specific.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

Rob Biedenharn wrote:

last_id = MyModel.maximum('id')

Anything else is likely database specific.

We do that one in tests to find the last-added record.

Wouldn't the 'id' roll over if we test >4 billion times?

Sure, but that's a different problem :wink:

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

Rob Biedenharn wrote:

Help greatly appriciated.

mymodel.save! puts "Last ID is #{mymodel.id}"

Is that helpful? If not, perhaps:

last_id = MyModel.maximum('id')

Anything else is likely database specific.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

Jordi had the solution, the id is updated on save/save!, just call the property you want from your model.

Just to set the record straight, that was my first suggestion, too. Just look! Since that only works when you were the one creating that last record, I also noted the other possibility. The OP's question sounded like the simple mymodel.id would work, but that's such an obvious thing (for *me*) that I offered something that might not have been obvious.

Using MyModel.maximum('id') to find the last inserted id is really not a good idea. The reason is that you can NEVER ensure that there wasn't another insert into your database in between your model.save! and MyModel.maximum('id') calls no matter how short the time frame in between them.

So this is not a good practice at all.

Hope this helps.

I don't recall if the OP (Rudy?) has chimed back into the discussion, but it would help if he clarified how/if this has helped.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

Maybe I’m paranoid, but doesn’t that run the risk of a different row getting created before you can do that?

Hi guys, thanks for all the help. Greatly appriciated. It did clarify it. What I use now (and tell me please if this is wrong for any reason) is

car=Car.create!(:make => foo)

after that, car.id is indeed the id from the newly inserted record.

In a way, once you know, it seems so obvious, and it was stated somewhere in the Agile Web Development book as well. (p310) But it was hard to find - as usual for me. :frowning:

I hope that, by having it written out here, as you guys so greatly did, anyone looking for the answer on this question can now find it here as well. This discussiongroup can not be praisedf enough! Rudy

Rudy wrote:

car=Car.create!(:make => foo)

after that, car.id is indeed the id from the newly inserted record.

Someone here doesn't remember the Bad Old Days...

- you had to research how to query that freaking ID correctly - you had to research AGAIN to figure out how to find it      for each type of database you use - you had to research _AGAIN_ to make sure the number      didn't change when you went to different database      connections and/or threads - you had to give up and re-query the record you just wrote      back out of the database, just to robustly get its ID

When someone scarred by all those experiences tries to use ActiveRecord, and the documentation doesn't exactly say "the correct id always pops into your database record when the wind blows", you tend to forget how lean and creative all your database activities can be!

George Bailey wrote:

We do that one in tests to find the last-added record.

Maybe I'm paranoid,

Maybe you are test-infected? (-;

but doesn't that run the risk of a different row getting created before you can do that?

Yes. I just thought of a fix:

   record = assert_latest Record do        get :create_record, :value => 'foo'    end

   assert_equal 'foo', record.value

If we assume monotonic IDs, we can implement that by fetching Record.maximum(id) before the block, then fetching Record.find_by_id(id + 1) after the block. Now we know we have the first new Record which our tested code created. That's probably more robust, and test-isolating, than fetching the very last record!

I think I'l go write that one and retrofit it into a few places...

Jean Nibee wrote:

OR, easier than all that, drop the database / tables in between tests and use migrations / fixtures to 'build them up' again when ready. May add a bit of overhead to you timing for execution but it will reset all the internal counters in the DB and you'll always restart at '1'. (Or whatever you set minimum is).

Occurs to me that many of our projects have a "super-test" Rake task to rebuild the database just like that.

So, no 4-billionth test run bug (or award) for us!

And now if one slips in behind you, you can have a valid record that fails that test :wink:

George Bailey wrote:

   record = assert_latest Record do        get :create_record, :value => 'foo'    end

   assert_equal 'foo', record.value

And now if one slips in behind you, you can have a valid record that fails that test :wink:

That's why we run the tests every few edits. The faster they go, the more we write, and the sloppier they can get. An edit that pushed a record in where we don't suspect it is a bad edit, even if the user is indeed waiting for that record.

When the test fails, we back off and try again. If the test fails again, we might examine why, and we might find a cleverer and more decoupled way to add that record.

So frequent test runs make sloppy tests _more_ valuable and cost-effective than arbitrarily correct and complex tests.

In my case

       #I CREATE THE ADD       @anuncio = Anuncio.new(params[:anuncio])       @anuncio.categoria_id = @cat.id       @anuncio.ip = request.remote_ip

      #THEN I SAVE IT       if @anuncio.save

        # I GENERATE THE SEO LINK USING THE ID OF THE LAST INSERT         t = @anuncio.titulo.to_s.downcase.strip.gsub(/[^-_ \s[:alnum:]]/, '').squeeze(' ').tr(' ', '_')         (t.blank?) ? '_' : t         @anuncio.seo = t + '_' + @anuncio.id.to_s

        #THEN SAVE AGAIN         @anuncio.save

I dont like this too mutch, 2 saves for the same inserted add, but thats the way things go.

Bruno Sacco

Mindstorm wrote:

In my case

       #I CREATE THE ADD       @anuncio = Anuncio.new(params[:anuncio])       @anuncio.categoria_id = @cat.id

Would this be safer?

     @anuncio.categoria = @cat

      @anuncio.ip = request.remote_ip

      #THEN I SAVE IT       if @anuncio.save

        # I GENERATE THE SEO LINK USING THE ID OF THE LAST INSERT         t = @anuncio.titulo.to_s.downcase.strip.gsub(/[^-_ \s[:alnum:]]/, '').squeeze(' ').tr(' ', '_')         (t.blank?) ? '_' : t         @anuncio.seo = t + '_' + @anuncio.id.to_s

@anuncio.update_attribute :seo, t + ...

Then no save. Do it in one line.

        #THEN SAVE AGAIN         @anuncio.save

I dont like this too mutch, 2 saves for the same inserted add, but thats the way things go.

Can you override the after_create handler? That or a similar handler might be called after the first time a model record is created, and when its id field is ready.