rails db:fixtures:load を使おう

こんにちは。クライアントワーク事業部でサーバサイドエンジニアをやってる@kazasikiです。
今年もやってきましたAdvent Calendar。1日目は少し緊張しますね。
挨拶はほどほどにして、さっそくプログラムの話を始めましょう。

クライアントワーク事業部とRailsについて

エンジニアの方々であれば、Railsの紹介は不要かと思います。現在クライアントワーク事業部では多くのWebサイトをRailsで構築しています。比較的短い期間で小〜中規模のWebサイトを作り上げることが多く、品質と生産性を安定させる意味でも規約が多いWebフレームワークを使うのは理にかなった選択です。(少なくとも私はそう思ってます。)
しかし、規約が多いRailsの中でも、人によって違う使い方をしてしまう機能がいろいろとあります。今回はその一つとしてrails db:seedやその周辺を取り挙げます。

Railsのデータファイルに対する考え方

まず、Railsにはデータを記述するファイルとして

  • db/seeds.rb
  • test/fixtures/*

の2つがあります。

db/seeds.rbはその名の通り、シードデータを記述するファイルです。rails db:seedを実行すると読み込まれて実行されます。
test/fixtures/*rails testでminitestを実行する際に使用されるデータです。

この2つのうち、特にdb/seeds.rbについて個々人で認識がズレることが有ります。ざっくりいうと、

  • アプリケーション動作に必須な所謂マスタテーブルのデータ
  • 開発環境などに使う動作確認用のデータ(とりあえず全テーブルに5件ぐらい入れとくやつ)

のどちらを書くファイルなのかという点です。
解決策としては環境ごとに投入する初期データを変えるのような方法が簡単でしょう。

しかし、Railsは「動作確認用のデータ」を入れるファイルを決めていないのでしょうか?そうではありません。
Railsはそういったデータを入れるファイルをtest/fixtures/*とした上で、rails db:fixtures:loadを提供しています。

rails db:fixtures:load を使う

test/fixtures/*rails testのためのデータを記述するファイルというイメージが強いですが、テストをちゃんと書いているのであれば動作確認に必要なデータは一通り揃っている筈です。
rails db:fixtures:loadtest/fixtures/*のデータをrails testのときと同じやり方でdevelopment用のDBに投入してくれます。

これは以下のような分かりやすい住み分けを提供してくれます。

  • db/seeds.rb はアプリケーション動作に必須なデータを記述するファイル
  • test/fixtures/* は動作確認用のデータを入れるファイル

開発環境ではrails db:create db:migrate db:seedを基本的には実行しつつ、程よいデータがほしければ適宜rails db:fixtures:loadを実行すればよいということです。

rails db:fixtures:load で困ること

とはいえ、rails db:fixtures:loadを使わない正当な理由も沢山あります。

  • そもそもあんまりテストを書いてないから test/fixtures/* が充実してない
  • 標準のfixturesではなく、factory_girlなどのgemを使っている。
  • yml(+erb)はテストデータのバリエーションの作り込みがやりにくい

3番目のやつはRailsGuideにあるような以下のような書き方がyml(erb)だと少しやり難いという話です。

# db/seeds.rb
5.times do |i|
  Product.create(name: "Product ##{i}", description: "A product.")
end
# test/fixtures/products.yml
<% 5.times do |i| %>
product_<%= i %>:
  name: <%= "Product ##{i}" %>
  description: A product.
<% end %>

まとめ

以上、Railsプロジェクト内でのデータファイルの住み分けの話でした。
rails db:fixtures:loadをうまく使ってる人が少ない気がしたので書きました。

明日は、@KAMEDAkyosuke さんがiOSに追加された話題の機能について書いてくれるらしいです。お楽しみに!