71

I was wondering if there is a way to find the newest record in a table in rails3?

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
Elliot
  • 13,580
  • 29
  • 82
  • 118
  • 1
    We need to know more about the table you are talking about. Is there a datetime field that is automatically updated when a record is added and/or changed? – the Tin Man Feb 02 '11 at 03:38

5 Answers5

146

Given a Post model, you could do @post = Post.order("created_at").last

(The reason I didn't just do a @post = Post.last is because that always defaults to sort by your primary key (usually id). Most of the time this is fine, but I'm sure there's a scenario where that could cause problems (e.g. setting custom IDs on records, database changes which affect the primary key sequencing/autonumbering, etc.). Sorting by the created_at timestamp ensures you are really getting the most recent record).

Dylan Markow
  • 123,080
  • 26
  • 284
  • 201
  • 12
    Be sure to index that created_at field if using this method. – jemminger Feb 02 '11 at 23:56
  • 1
    In Rails 4, you can also add the line `default_scope { order(created_at: :asc) }` to the Post model to ensure that `Post.last` behaves as expected. – sambecker Sep 01 '16 at 17:20
24

While dmarkow's answer is technically correct, you'll need to make an index on created_at or risk an increasingly slow query as your database grows.

If you know that your "id" column is an auto-increment primary key (which it likely is), then just use it since it is an index by definition.

Also, unless AREL is optimized to select only one record in a find(:last), you run the risk of making it select ALL records, then return you just the last one by using the "last()" method. More efficient is to limit the results to one:

MyModel.last(:order => "id asc", :limit => 1)

or

MyModel.first(:order => "id desc", :limit => 1)
jemminger
  • 5,133
  • 4
  • 26
  • 47
  • 14
    `@post = Post.order("created_at").last` actually does do the right thing. Console output is something like `SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT 1` – PhilT Nov 17 '15 at 14:34
3

you may run into ambiguity issues using created_at on a sufficiently high-traffic table.

eg. try:

INSERT INTO table (created_at) VALUES ( NOW() );
INSERT INTO table (created_at) VALUES ( NOW() );

..has the potential to have the same created_at, which only has 1 second of resolution. a sort would return them in no particular order.

you may be better off storing a microtime value and sorting on that.

RUN-CMD
  • 340
  • 3
  • 12
2

Try, for a model named ModelName:

record = ModelName.last
Substantial
  • 6,684
  • 2
  • 31
  • 40
Sam Ritchie
  • 10,988
  • 4
  • 42
  • 53
  • 5
    This does not take into account the sort order for the table. It would fail if using postgres database – jamesc Mar 05 '13 at 23:01
  • 4
    It would fail...great. What would you do to avoid the fail? – zero_cool Nov 18 '14 at 18:34
  • @jamesc I'm using this with postgres and it works, what are you referring to? – Lerk Jun 04 '23 at 16:30
  • @Lerk There is no default sort order for Postgres records, as you should be aware, it is not the primary ID key, the last record could be anything and the above will only work if explicitly setting the sort order that you need on the model or including it as part of the .last call with a call to .order or adding an ORDER BY clause – jamesc Jun 05 '23 at 02:46
  • @Lerk as my first comment mentions and as others have pointed out both in answers and comments that the sort order is an issue, maybe order by primary key if it's an auto incremented field is the best option otherwise maintain another field somehow that determines the correct sort order but I guarantee that this does NOT work for you, you just think it does – jamesc Jun 05 '23 at 03:01
  • @jamesc but that's what I'm talking about. The default postgres config uses an autoincremented (int?) id and is sorting using that when using `Entity.last` without any further configuration. So "it would fail if using postgres" is not true. – Lerk Jun 06 '23 at 10:48
  • @Lerk that just is not true, it's just what you think is true, From Postgres documentation " If sorting is not chosen, the rows will be returned in an unspecified order. The actual order in that case will depend on the scan and join plan types and the order on disk" https://www.postgresql.org/docs/current/queries-order.html as has been pointed out by many others already, opf course you may continue on in your approach but it will haunt you at some point – jamesc Jun 08 '23 at 05:15
  • @jamesc that might be true, but the `.last` method doesn't come from postgres. The active_record documentation (`/ruby-3.0.6/gems/activerecord-6.1.7/lib/active_record/relation/finder_methods.rb:133`) clearly states that "If no order is defined it will order by primary key". – Lerk Jun 09 '23 at 21:56
1

Yes, you can use the method .last

So if your model is called Post then:

>> Post.last
=> #<Post ...>
DanneManne
  • 21,107
  • 5
  • 57
  • 58
  • 1
    this is not always true in some cases, one of those is when the id type is randomely generated string, so to be in the safe side, use Post.order("created_at DESC").first to get the newest post created based on the creation time, or if you depend on the updated_at, it can be Post.order("updated_at DESC").first – ELTA May 08 '19 at 11:34