ヨージとプログラミング

プログラミング勉強の記録

【Rails】Record.lastで取り出せるのはどんなデータか?

作成中のアプリの挙動がおかしいことに気づいた

いきなり私事ですが、私の作成している体重記録アプリで、最後に記録した体重をDBから取得するのですが、こうしました

# あるuserの最後のレコードの体重を取得
@last_record = user.records.last.weight

結果的に言うと、本番環境であればこのコードは正です。 しかし、開発環境では少し挙動がおかしくなりました(私の未熟さ故なのですが…)

seedsでランダムな記録日を生成したせいでlastが狂う

以下のようなseed.rbを書いてユーザーとrecordを生成しました。

r = Random.new()

50.times do |n|
  name = Faker::Name.name
  email = "exsample-#{n+1}@example.com"
  height = r.rand(150.0..185.0).round(1)
  password = 'password'
  User.create!(
    name: name,
    email: email,
    height: height,
    password: password,
    password_confirmation: password
  )
end

r2 = Random.new()
users= User.order(:created_at).take(38)

60.times do |n|
  weight = r2.rand(55.0..100.0)
  to = Time.zone.now
  from = to - 60.days

  users.each do |user|
    user.records.create!(
      weight: weight,
      created_at: r2.rand(from..to)
    )
  end
end

長いですが、注目してほしいのこの部分

60.times do |n|
       〜
  users.each do |user|
    user.records.create!(
      weight: weight,
      created_at: r2.rand(from..to)
    )
  end
end

私のappではcreated_atをそのままrecordの記録日とする関係上、seedで作成するrecordのcreated_atを上手く散らす必要があります。そこで、randメソッドで乱数化しています。
そこで本題のRecord.lastがどうなるかですが、私としては”最新” = ”created_atが最も新しい" 記録を想定していたわけですが、全然違うものが取得されてしまいました…

Record.lastの"last"は"idのlast"

分かってみれば当たり前のことかもしれませんが…consoleでlast確認してみると, 'id'でorderされていることが分かります。つまり、lastで得られるものは、最後に記録したrecordになります。
本番環境では、 必ず「最後に記録したrecord」= 「最新日」となりますので問題は無いわけです!

irb(main):008:0> user.records.last
=> Record Load (0.7ms)  SELECT  `records`.* FROM `records` WHERE `records`.`user_id` = 52 ORDER BY `records`.`id` DESC LIMIT 1

「記録日が最も新しい」を取得するにはどうするか?

開発環境でも最新日を取得したかったので、このように書き直しました。

irb(main):011:0> user.records.order(created_at: :desc).first
=> Record Load (0.7ms)  SELECT  `records`.* FROM `records` WHERE `records`.`user_id` = 52 ORDER BY `records`.`created_at` DESC LIMIT 1

recordをcreated_at降順で並び替えて、firstを取得しました。 もちろん、昇順にしてlastでも可です。