11/2 RailsチュートリアルやRailsガイドの中の人である安川様より本記事をお褒め頂きました🎉
目的
Railsチュートリアルにて、seeds.rb
を用いて任意の数のユーザーとそれに対するマイクロポストの作成をおこないました。
先輩エンジニアに見てもらうと「リファクタリングできるよ〜」とのことだったので、その方法をまとめます。
何が問題なのか?
まずはcreate
メソッドの使い方をおさらいします。
例として今、number
というキーをもつNumber
モデルから、インスタンスを5つ作成することにします。
Number.create!(number: 1)
Number.create!(number: 2)
Number.create!(number: 3)
Number.create!(number: 4)
Number.create!(number: 5)
毎回Number.create!
を実行するパターンです。
この方法ではcreate!
メソッドを5回おこなっていることになります。
create!
メソッドは実行するとSQL文を発行し、DBへアクセスします。
つまりこの方法では5回DBにアクセスし、それだけ負荷が大きいということです。
Number.create!( [
{number: 1},
{number: 2},
{number: 3},
{number: 4},
{number: 5}
] )
create!
メソッドを一回実行するだけで5つのインスタンスを作成する方法です。
同じキーをもつ複数のハッシュは配列化していっぺんにcreate
メソッドの引数にとることができます。
配列内は各インスタンスのキーとバリューを指定したハッシュの形をとります。
しかしこれでも、毎回キーを指定する必要がありスマートな書き方ではありません。
numbers_array = 5.times.map {|n| {
number: n
} }
Number.create!(numbers_array)
そこで、numbers_array
という変数を用意し、そこに配列を代入します。
配列の指定方法はmap
メソッドとtimes
メソッドを組み合わせます。
ブロックの中ではn
という変数を使用することができるので、バリューをこのように指定します。
定義したnumbers_array
をNumber.create!
の引数にすることでインスタンスを生成することができます。
手順
それでは、Railsチュートリアルのseeds.rb
をリファクタリングしていきます。
ユーザーをまとめて生成する
99.times do |n|
name = Faker::Name.name
email = "example-#{n+1}@railstutorial.org"
password = "password"
User.create!(name: name,
email: email,
password: password,
password_confirmation: password,
activated: true,
activated_at: Time.zone.now)
end
この生成方法では、User.create!
を99回おこなっていることになります。
つまり、DBへのアクセスが99回おこなわれており、負荷が大きいです。
create!
メソッドが1回で済むように下のようにリファクタリングしました。
# 各キーをもつハッシュが99個入った配列をつくる
users_array = 99.times.map {|n| {
name: Faker::Name.name,
email: "example-#{n+1}@railstutorial.org",
password: "password",
password_confirmation: "password",
activated: true,
activated_at: Time.zone.now
} }
# create!の引数にusers_array配列をとる
User.create!(users_array)
まず、users_array
という、99人のユーザー情報が入った配列を作成します。
このとき、99.times.map
で複数のハッシュをいっぺんに作っていることに注目してください。
その後、User.create!
の引数にusers_array
配列をとることでcreate!
メソッドの実行が一度で済むようにしました。
これによりDBへのアクセスも1回で済み、負荷を小さくすることができます。
ユーザーの一部を対象にマイクロポストを生成する
users = User.order(:created_at).take(6)
50.times do
content = Faker::Lorem.sentence(word_count: 5)
users.each { |user| user.microposts.create!(content: content) }
end
この生成方法は、6人のユーザーに対して50回ずつcreate!
をしていることになります。
つまり、6×50=300回もDBにアクセスしています。
# Userから6人取り出し、each文を回す
User.order(:created_at).take(6).each do |user|
# 50個のcontentを持つハッシュを作成し、contents_array配列に代入
contents_array = 50.times.map {{
content: Faker::Lorem.sentence(word_count: 5)
}}
# create!の引数にcontents_array配列をとる
user.microposts.create!(contents_array)
end
まず、User
から6人を取り出します。
each
文の中では以下の内容が実行されます。
-
content
キーをもつ50個のハッシュを生成し、contents_array
配列に代入 -
each
で定義した6人のuser
に対し、create!
メソッドを実行 -
create!
メソッドの引数にはcontent_array
配列をとる
これにより、create!
メソッドは6回で済むようになりました。
参照