はじめに
本番環境にsshしてrails c
を使ってデータを弄るとかはしたくないですよね。
まさか、まさか、そんなこと誰もしていないと思います...。
...と言いつつ、まだ環境が整い切ってない現場では、稀によくある話だとも思っています。
実際僕もたまにやってしまっていたので、それを解決する手段ないかと検討していました。
今回はそんな課題に対して、「こんな手法の解決策ができるかな」ってことを試したくて、Gemを作ってみました。(ちなみに、Gemはほぼ作ったことないGem初心者です。)
また、このGemはrails8系から入ったscriptフォルダ
も関連しています。
この記事では、
- データ移行の課題と
- (あまり有名でないと思うので)scriptフォルダの説明と
- 作ったGemの話
をしていきます。
が、まずはどんなもの作ったか紹介した方がわかりやすいので、作ったものの紹介です。
作ったGem - Scriptor
これは何ができるのかというと、
- ブラウザからscriptフォルダのコードが閲覧できて
- ブラウザからscriptフォルダのコードが実行できて
- ブラウザからscriptフォルダのコードの実行履歴が見られる
みたいなことができます。リポジトリはこちらです。
ってことで、続いてこのGemを作った背景を書いてきます。
データ移行どうやってる?
データ移行の方法は、よく話題になるトピックと思います。
これまでのデータを修正するやり方は、maintenance_tasks gemを使ったり、data_migrate gemを使ったり、はたまた rake task
を実行することだと思います。
maintenance_tasks gem は私も普段お仕事でお世話になっています。
Rails Guide には
データをマイグレーションで操作するよりも、maintenance_tasks gemの利用を検討してください。このgemは、スキーマのマイグレーションを妨げることなく、安全かつ簡単に管理できる方法で
と、maintenance_tasks gemの利用が勧められていますね。
一方で、maintenance_task
を導入するほどではないような場合、rake task
を書いて実行することもメジャーな手法と思います。
maintenance_task
が出てくる以前は、rake task
での実行が非常に多かった印象です。
そんないろいろな手段があるなか、(全く紹介されているのを見かけないので有名ではない気がしますが) Ruby on Rails 8.0.0からは、 script
フォルダというのが誕生しました。
このプルリクエストで作られています。
scriptフォルダについて
Rails Guideには、scriptフォルダについて
使い捨て、または汎用のスクリプトやベンチマークをここに置きます。
と説明されています。scriptフォルダの使い方が書かれているscript/USAGEにも
Generate a one-off or general purpose script, such as a data migration script, cleanup script, etc.
つまり「単発のデータ移行のためのscriptを生成する」と書いていそうです。
ってことで、実はひっそりと、Rails8系から、単発のデータ移行のためにscript
フォルダってものが提供されるようになりました。
scriptフォルダの使い方
このscriptフォルダの使い方は非常に簡単です。
bin/rails generate script my_script
と実行すると script/my_script.rb
ファイルが生成されます。
そしてscript/my_script.rb
ファイルはデフォルトでは、以下のようになっています。
require_relative "../config/environment"
# Your code goes here
非常に簡単ですね。このファイルをいじってRailsのコードを書いていきます。
例えば、以下のように書いてデータの移行を行なったりができます。
require_relative "../../config/environment"
title, body = ARGV
if post = Post.find_by(title: title)
post.update!(body: body)
puts "Post updated!"
else
Post.create!(title: title, body: body)
puts "Post created!"
end
このscriptフォルダの実行方法は、例えば以下です。
ruby script/my_script.rb hello world
ってことで簡易的なものを実行するのにはscriptフォルダも良さそうです。
もっとscriptフォルダの背景について知りたい場合は Is there any “official” way to organize one-off scripts? が参考になるかもしれません。
このスクリプトをブラウザから実行させたいし実行履歴を管理したい
このscriptフォルダ、簡易的データ移行については、そこそこ便利だなって思ったのですが...。
この実行のために本番環境にsshするのとかは、したくないです。
そしてこの実行のログも念の為とっておきたい、とかの欲も出てきました。
その欲を実現しようと思って作ったのが今回のScriptorというGemです。
Scriptorの簡単な説明
このGemは
- ブラウザからscriptフォルダのコードが閲覧できて
- ブラウザからscriptフォルダのコードが実行できて
- ブラウザからscriptフォルダのコードの実行履歴が見られる
ようなものです。
例えば、scriptフォルダが以下のようになっているとします。
❯ tree script
script
├── migration
│ ├── hoges.rb
│ └── posts.rb
└── my_script.rb
2 directories, 3 files
このとき、http://localhost:3000/scriptor にアクセスすると以下のようなscript一覧画面が表示されます。
scriptの詳細ページへ行くと、そのスクリプトのコードが載っています。
このページには 🛠️Run Script
ボタンがあり、そのボタンを押すと、このページのコードが実行できます。
また Scriptの実行に引数が必要ならば、textfieldに引数を書くとそれを反映してくれます。
実行履歴では
- ステータス(running, success, error)
- 開始日時
- 終了日時
- 実行コマンド
- 実行したファイル
などを保持しています。
導入
導入も簡単と思います。
-
bundle add scriptor
で scriptor gemを追加 -
bin/rails generate scriptor:install
を実行-
config/routes.rb
にmount Scriptor::Engine => "/scriptor"
が記載されます -
db/migrations/****_create_scriptor_executions.scriptor.rb
ファイルが作成されます
-
- scriptフォルダにスクリプトを作ると、http://localhost:3000/scriptor ページにスクリプト一覧が並びます
なかなか簡単で便利?なGemができた気がしています。
終わりに
データ移行の方法の一つとして、Rails8系からscriptフォルダが出ました。
これをうまく使えないかなと思って、今回Rails EngineのGemを作ったりしてみました。
Gem作りは慣れていないですが、楽しくやってたらちょっと良いGemできたなって気分でいます。
が、まだまだ足りていないこととか沢山ある(英語の説明もないし、テストも全然書けていない)ので、Contributeなんかも大歓迎です。Starも嬉しいです。
ってことでscriptフォルダの話と作ったGemの話は終わります。ありがとうございました。