【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でも可です。