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.


Jordi

On Jul 5, 2007, at 7:27 AM, Rudy 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 B. http://agileconsultingllc.com
[email protected]

On Jul 5, 2007, at 10:57 AM, Phlip wrote:

Phlip
Test Driven Ajax (on Rails) [Book]
“Test Driven Ajax (on Rails)”
assert_xpath, assert_javascript, & assert_ajax

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

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

Rob B. 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?


Phlip
Test Driven Ajax (on Rails) [Book]
“Test Driven Ajax (on Rails)”
assert_xpath, assert_javascript, & assert_ajax

Phlip wrote:

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

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


Phlip
Test Driven Ajax (on Rails) [Book]
“Test Driven Ajax (on Rails)”
assert_xpath, assert_javascript, & assert_ajax

If you do that many tests I’m sending you a medal. :wink:

If you that concerned use a bigger unsigned data type (like say unsigned
long int in Mysql) or something like a 64 bit GUUID or Serial UUID.

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).

HTH.

Rob B. wrote:

On Jul 5, 2007, at 7:27 AM, Rudy 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 B. http://agileconsultingllc.com
[email protected]

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

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.

On Jul 5, 2007, at 1:56 PM, Jean N. wrote:

Anything else is likely database specific.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

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.

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 B. http://agileconsultingllc.com
[email protected]

On Jul 5, 2007, at 8:57 AM, Phlip wrote:

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

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

Rob B. wrote:

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.

Sorry I should have given credit to EVERYONE on the proper solutions, I
just took the lazy way out and sent a kudo’s to Jordi.

My apologies.

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!


Phlip
http://c2.com/cgi/wiki?ZeekLand ← NOT a blog!!

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 D. 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

George B. 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

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…


Phlip
Test Driven Ajax (on Rails) [Book]
“Test Driven Ajax (on Rails)”
assert_xpath, assert_javascript, & assert_ajax

On Jul 6, 2007, at 6:40 PM, Phlip wrote:

Yes. I just thought of a fix:

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:

Jean N. 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!


Phlip

George B. 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.


Phlip
Test Driven Ajax (on Rails) [Book]
“Test Driven Ajax (on Rails)”
assert_xpath, assert_javascript, & assert_ajax

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.


Phlip
http://c2.com/cgi/wiki?ZeekLand ← NOT a blog!!

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