If you do that many tests I’m sending you a medal.
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).
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.
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.
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.
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!
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.
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
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…
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!
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
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.
#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.
#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
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.