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回で済むようになりました。
参照