1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Rails】Railsチュートリアルのseeds.rbをリファクタリングする

Last updated at Posted at 2022-11-01

11/2 RailsチュートリアルやRailsガイドの中の人である安川様より本記事をお褒め頂きました🎉

目的

Railsチュートリアルにて、seeds.rbを用いて任意の数のユーザーとそれに対するマイクロポストの作成をおこないました。
先輩エンジニアに見てもらうと「リファクタリングできるよ〜」とのことだったので、その方法をまとめます。

何が問題なのか?

まずはcreateメソッドの使い方をおさらいします。
例として今、numberというキーをもつNumberモデルから、インスタンスを5つ作成することにします。

レベル1
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にアクセスし、それだけ負荷が大きいということです。

レベル2
Number.create!( [
  {number: 1},
  {number: 2},
  {number: 3},
  {number: 4},
  {number: 5}
] )

create!メソッドを一回実行するだけで5つのインスタンスを作成する方法です。
同じキーをもつ複数のハッシュは配列化していっぺんにcreateメソッドの引数にとることができます。
配列内は各インスタンスのキーとバリューを指定したハッシュの形をとります。
しかしこれでも、毎回キーを指定する必要がありスマートな書き方ではありません。

レベル3
numbers_array = 5.times.map {|n| {
  number: n
} }
Number.create!(numbers_array)

そこで、numbers_arrayという変数を用意し、そこに配列を代入します。
配列の指定方法はmapメソッドとtimesメソッドを組み合わせます。
ブロックの中ではnという変数を使用することができるので、バリューをこのように指定します。

定義したnumbers_arrayNumber.create!の引数にすることでインスタンスを生成することができます。

手順

それでは、Railsチュートリアルのseeds.rbをリファクタリングしていきます。

ユーザーをまとめて生成する

before
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回で済むように下のようにリファクタリングしました。

after
# 各キーをもつハッシュが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回で済み、負荷を小さくすることができます。

ユーザーの一部を対象にマイクロポストを生成する

before
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にアクセスしています。

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

参照

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?