Ruby on Rails

【Rails】便利なActiveRecordに関するメソッド

RailsのActiveRecordで使える便利メソッドを集めてみました。

first_or_create

条件に一致したレコードを持っている場合に一致した最初のレコードを、ない場合は新規作成をするメソッドです。このメソッドは引数にブロックを渡すことができ、属性を保存することができます。

User.where(email: 'hoge@example.com').first_or_create do |user|
  user.name = 'sakai'
  user.phone = '080-1234-5678'
end

ただし、属性の更新をすることはできません。これで結構ハマってしまうことがありました。

user = User.create(email: 'hoge@example.com')
User.where(email: 'hoge@example.com').first_or_create do |user|
  user.name = 'sakai'
  user.phone = '080-1234-5678'
end

=> #<User id: 4, email: "hoge@example.com", name: nil, phone: nil, created_at: "2021-07-31 22:06:55", updated_at: "2021-08-12 00:48:23">

find_each

eachメソッドは全件データをメモリに展開して処理を開始します。それだと十分にメモリに載るデータ量であれば問題ないですが、数百万、数千万というデータ量になってくると処理が重くなることがあります。そういう場合にfind_eachを使います。

find_eachを使うとORDER BYでid順に並び替えて、デフォルトでは1000件ごとに処理を行います。

User.where(age: 28).each do |user|
  user.name = '28歳の人'
  user.save
end

User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`age` = 28
User Update (0.7ms)  UPDATE `users` SET `name` = '28歳の人', `updated_at` = '2021-08-14 21:30:30' WHERE `users`.`id` = 4

User.where(age: 28).find_each do |user|
  user.name = '28歳の人'
  user.save
end

User Load (0.7ms)  SELECT  `users`.* FROM `users` WHERE `users`.`age` = 28 ORDER BY `users`.`id` ASC LIMIT 1000
User Update (0.5ms)  UPDATE `users` SET `first_name` = '28歳の人', `updated_at` = '2021-08-14 21:36:52' WHERE `users`.`id` = 4

ActiveRecord::AttributeMethods#attributes

カラムの属性値をハッシュ形式で取ることができます。

article.attributes
=> {"id"=>1,
 "title"=>"Harry Potter And The Sorcerer’s Stone",
 "content"=>"aa",
 "created_at"=>Tue, 13 Dec 2022 17:36:38.762864000 JST +09:00,
 "updated_at"=>Wed, 14 Dec 2022 06:39:02.427697000 JST +09:00,
 "is_public"=>true,
 "priority"=>"important"}

このメソッドは下のようにカラム名と同じ名前のインスタンスメソッドを持っている場合に便利です。

class Article < ApplicationRecord
  def title
    # title カラムの値を大文字にする
    self.attributes[:title]&.upcase
  end
end
# 上のメソッドを通過するので大文字で表示される
article.title
=> "HARRY POTTER AND THE SORCERER’S STONE"

# カラム属性値経由で取得するため、上のメソッドを通過しない
article.attributes["title"]
=> "Harry Potter And The Sorcerer’s Stone"

# こちらでも同じ
article["title"]
=> "Harry Potter And The Sorcerer’s Stone"

個人的には attributes メソッドを使ったほうが、読みやすいので好きです。

さいごに

またなにかあれば追記していこうと思います。

ABOUT ME
sakai
東京在住の30歳。元々は車部品メーカーで働いていてましたが、プログラミングに興味を持ちスクールに通ってエンジニアになりました。 そこからベンチャー → メガベンチャー → 個人事業主になりました。 最近は生成 AI 関連の業務を中心にやっています。 ヒカルチャンネル(Youtube)とワンピースが大好きです!