9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby on RailsAdvent Calendar 2024

Day 3

【Rails】Rakeタスクによる初期データ投入

Last updated at Posted at 2024-12-01

はじめに

今まで初期データ(ダミーデータ)を投入するとき、とりあえずrails db:seedコマンドを実行していました。
rakeタスクでも同様のことができると知ったので、こちらにまとめます。

Rakeタスクとは

Rakeは、Rubyで書かれた特定の処理をタスクとして、まとめて実行するための仕組みです。
このRakeが実行する処理をRakeタスクと呼びます。

Rubyで書かれた、タスクを定義・管理するためのビルドツールです。
C言語やUnixでいうところのmakeみたいなものらしいです。

Rakeタスクのメリット

  • 作業の自動化: 手作業で行っていた面倒な作業を自動化できます
  • 再利用性: 一度定義したタスクは、何度でも実行できます
  • 可読性: Rubyのコードで記述するため、他の開発者でも理解しやすくなります

RakeタスクとSeedの違い

Seedの特徴

  • 目的: データベースの初期化
  • 機能: 特定のテーブルに初期データを挿入する
  • 実行方法: rake db:seedコマンドで実行
  • ファイル: db/seeds.rbファイルにRubyのコードで記述
  • 特徴:
    • データベースの初期状態を設定するためのシンプルな仕組み
    • 具体的なデータの挿入に特化している
    • 比較的簡単な構造で記述できる

Rakeタスクの特徴

  • 目的: 様々な処理の自動化
  • 機能: データベースのマイグレーション、テストの実行、データの生成など、幅広い処理が可能
  • 実行方法: rake <タスク名>コマンドで実行
  • ファイル: lib/tasksディレクトリに作成したRakeファイルにRubyのコードで記述
  • 特徴:
    • 柔軟性が高く、複雑な処理も実装できる
    • 独自のタスクを定義できる
    • seed機能もRakeタスクの一種と考えることができる

上記のようにseedを実行するだけではなく、データベースのマイグレーションなど幅広い処理が実行可能です。
例えば、rails db:migrate:resetrails db:seedとコマンドを一個ずつ実行していた作業がrakeタスクで1回にまとめられます。

タスクファイル

ファイル作成方法

$ rails g task タスク名

今回作成したファイル

lib/tasks/dummy_all_data.rake
namespace :dummy do
  desc "ダミーデータの投入"
  task all_data: :environment do
    ActiveRecord::Base.transaction do
      puts '--- start ---'

      puts '--- DB migrate reset ---'
      Rake::Task['db:migrate:reset'].invoke

      puts '--- dummy:userinfo ----'
      Rake::Task['dummy:user_info'].invoke

      puts '--- end ---'
    end
  end
end

補足

  • namespace: タスクを整理するための名前空間を定義しています
  • desc: タスクの説明文です。コマンドラインでrake -Tを実行すると、この説明文が表示されます
  • :environment: 、このタスクを実行する前にRailsの環境が設定されます。どうやらrakeタスクを実行する時にrails内部でこのenvironmentを実行しているみたいです
  • Rake::Task: 上記ではdb:migrate:resetというタスクで全てのマイグレーションを取り消してDBを再構築。その後にdummy:user_infoというタスクでユーザーデータを作成します

今回作成する初期データ

seedファイルではなく、タスクファイル上で以下のテストユーザーを作成してみます。

seedファイル

lib/tasks/dummy_user_info.rake
namespace :dummy do
  task user_info: :environment do
    begin
      users = [
        { name: 'test1', email: 'test1@example.com', password: 'password1', auth0_id: ENV['AUTH_ID1'], is_admin: false },
        { name: 'administrator', email: 'admin@example.com', password: 'password2', auth0_id: ENV['ADMIN_AUTH_ID'], is_admin: true }
      ]

      users.each do |user|
        User.create!(user)
      end
    rescue StandardError => e
      puts "--- ユーザー作成中のエラー ---"
      puts e.class, e.message
    end
  end
end

マイグレーションファイル

db/migrate/20241129232933_create_users.rb
class CreateUsers < ActiveRecord::Migration[7.2]
  def change
    create_table :users do |t|
      t.string :auth0_id
      t.string :name
      t.string :email
      t.string :password_digest
      t.boolean :is_admin
      t.datetime :discarded_at

      t.timestamps
    end

    add_index :users, [:auth0_id, :email], unique: true
  end
end

マイグレーションの補足

今回の主旨ではないですが、
add_index(ユニークなインデックス)を追加しているのは、モデルのバリデーションを通過しても、DBレベルでのユニーク制約によって重複するレコードの挿入を防ぐためです。

タスク実行結果

$ rake dummy_all_data

--- start ---
--- DB migrate reset ---
Dropped database 'my_app_development'
Dropped database 'my_app_test'
Created database 'my_app_development'
Created database 'my_app_test'
== 20241129232933 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0177s
-- add_index(:users, [:auth0_id, :email], {:unique=>true})
   -> 0.0151s
== 20241129232933 CreateUsers: migrated (0.0330s) =============================

--- dummy:userinfo ----
--- end ---

DBに登録されたユーザー

[1] pry(main)> User.all
=>   User Load (4.5ms)  SELECT `users`.* FROM `users` /* loading for pp */ LIMIT 11
[#<User:0x0000ffff9a1d8a40
  id: 1,
  auth0_id: "auth0|***************",
  name: "test1",
  email: [FILTERED],
  password_digest: [FILTERED],
  is_admin: false,
  discarded_at: nil,
  created_at: "2024-12-01 18:36:51.412288000 +0900",
  updated_at: "2024-12-01 18:36:51.412288000 +0900">,
 #<User:0x0000ffff9bd7adc0
  id: 2,
  auth0_id: "auth0|***************",
  name: "administrator",
  email: [FILTERED],
  password_digest: [FILTERED],
  is_admin: true,
  discarded_at: nil,
  created_at: "2024-12-01 18:36:51.791835000 +0900",
  updated_at: "2024-12-01 18:36:51.791835000 +0900">]

ユーザーが作成されました!

ユーザー作成失敗時

例えば、ユーザーのメールアドレスの@を省いてrakeタスク実行してみます。
email: 'test1@example.com'email: 'test1example.com'

(バリデーションは別途で実装しています)

$ rake dummy_all_data

--- start ---
--- DB migrate reset ---
Dropped database 'my_app_development'
Dropped database 'my_app_test'
Created database 'my_app_development'
Created database 'my_app_test'
--- dummy:userinfo ----
--- ユーザー作成中のエラー ---
ActiveRecord::RecordInvalid
バリデーションに失敗しました: メールアドレス は正しい形式で入力してください。
--- end ---

例外処理でバリデーションのエラーメッセージが表示されました。

タスク一覧

rake -T: Railsアプリケーションで定義されているすべてのRakeタスクとその簡単な説明を一覧表示するコマンドです。

$ rake -T 
(一部省略)
rake db:create                          # Create the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create...
rake db:drop                            # Drop the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all d...
rake db:encryption:init                 # Generate a set of keys for configuring Active Record encryption in a given environment
rake db:environment:set                 # Set the environment value for the database
rake db:fixtures:load                   # Load fixtures into the current environment's database
rake db:migrate                         # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
rake db:migrate:down                    # Run the "down" for a given migration VERSION
rake db:migrate:redo                    # Roll back the database one migration and re-migrate up (options: STEP=x, VERSION=x)
rake db:migrate:status                  # Display status of migrations
rake db:migrate:up                      # Run the "up" for a given migration VERSION
rake db:prepare                         # Run setup if database does not exist, or run migrations if it does
rake db:reset                           # Drop and recreate all databases from their schema for the current environment and load the seeds
rake db:rollback                        # Roll the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:cache:clear              # Clear a db/schema_cache.yml file
rake db:schema:cache:dump               # Create a db/schema_cache.yml file
rake db:schema:dump                     # Create a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `con...
rake db:schema:load                     # Load a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `confi...
rake db:seed                            # Load the seed data from db/seeds.rb
rake db:seed:replant                    # Truncate tables of each database for current environment and load the seeds
rake db:setup                           # Create all databases, load all schemas, and initialize with the seed data (use db:reset to also drop all databases ...
rake db:version                         # Retrieve the current schema version number
rake dummy:all_data                     # Create dummy data
rake dummy:user_info                    # Create new users
...

よく見ると、自分が作成したタスクも一覧に表示されています。

rake dummy:all_data # Create dummy data
rake dummy:user_info # Create new users

まとめ

seedとRakeタスクは、どちらもRailsアプリ開発においての目的や機能が異なります。seedはデータベースの初期化に特化しており、Rakeタスクはより柔軟に処理を自動化するための仕組みです。

シンプルなデータの挿入であればseed、より複雑な処理や独自の処理が必要な場合はRakeタスクが適しています。

参考記事

RailsでRakeタスクの作成
Ruby 3.3 リファレンスマニュアル library rake
Railsガイド rake

9
3
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
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?