💎

RubyのActiveRecordでMySQLに接続できるRubyGemを公開しました(SSH経由でも接続できるよ)

2024/12/16に公開

この記事は、Finatextグループ Advent Calendar 2024の16日目の記事です。

はじめに

こんにちは、Finatextのインシュアテック事業でバックエンドエンジニアをしている岸と申します。

今回は、RubyのActiveRecordでMySQLにSSH接続できるRubyGemを作成しましたので、その紹介をさせていただきます。

TL;DR

こちらのRubyGemを作ったのでぜひ使ってみてください!

https://rubygems.org/gems/active_record_mysql_repl

GitHubのREADMEにはサンプルのDBやコマンドのショーケースをたくさん用意しています👏🏻

https://github.com/nogahighland/active_record_mysql_repl

作成の背景

弊社ではバックエンド開発にGo言語をメインで使っているため、多くのメンバーはDB操作をするのにGUIツールを使用したりコンソールでSQLを実行することがほとんどですが、私はRuby on Railsでの開発経験があるため、 Rails consoleのActiveRecordのようにプログラマティックにDBを操作をしたい と思っていました。

空き時間で今回のRubyGemの原型となったツールを自作して日常的に使用していましたが、社内ミーティングのちょっとした時間に「こんなツール使ってるんですよ〜」と軽い気持ちで簡単なデモをしたところ、 「普通に有益だろ」(原文ママ)というフィードバックを頂きました。

原型となっていたツールは「The 野良ツール」という感じだったので、せっかくなので本年のAdvent Calendarに向けてOSSとして開発しました。OSSということもあり、GitHub側は可能な限り英語で表記しています(Copilotさまさま🙏🏻)

作成したRubyGem

ActiveRecordMysqlReplというRubyGem(Rubyのライブラリやコマンドラインツール)を作成しました。

https://rubygems.org/gems/active_record_mysql_repl
https://github.com/nogahighland/active_record_mysql_repl

Active Record Mysql Repl という頭文字を取って、インストールすれば army (あーみー)というコマンドで実行できるようになります。また、REPLという名前が付いている通り、Pry を使って対話型でDBを操作することができます。

余談ですが、Pry同様の対話型Rubyシェルである irb も最近はとても高機能化されているので、REPL機能として使えないかいつか試してみたいと思っています。

ActiveRecordとは??

「ActiveRecordって何?」という方もいるかもしれないので簡単に説明します。

ActiveRecordとは、Ruby on RailsのデファクトスタンダードなORMです。DBのテーブルをRubyのクラスとして扱うことができ、SQLを書かずにDBの操作ができるようになります。

テーブルから取得した値をRubyのオブジェクトとして扱うことができ、テーブル同士の関連性をメソッドチェーンで辿ることができたり、オブジェクトに変更を加えたのちそのオブジェクトの #save() メソッドを呼んで再びDBに保存することもできる仕組みです。

https://railsguides.jp/active_record_basics.html

例えば、以下のER図のようなテーブル構成のDBに対してログインしてインタラクティブに操作することができます。

army の使い方(概観)

詳しくはGitHubリポジトリのREADMEにインストール方法や使用方法のドキュメンテーションや、その中の sample_config/ ディレクトリにあるサンプルの設定ファイルを充実させていますので、ここでは概要をお伝えしたいと思います。
https://github.com/nogahighland/active_record_mysql_repl/

設定ファイル

.army.yml           # ルートの設定ファイル(デフォルトは ~/.army.yml)
  - databases.yml   # DBの接続情報
  - association.yml # テーブルの関連性定義ファイル
  - extensions/     # 拡張機能の設定ファイルディレクトリ
    - *.rb
  - pryrc           # pryの設定ファイル(デフォルトは ~/.pryrc)

以下のように、それぞれの設定を .army.yml からの相対パスとして記載します。

https://github.com/nogahighland/active_record_mysql_repl/blob/main/sample_config/.army.sample.yml

各種設定ファイルのサンプルには、JSONスキーマによる説明や補完も効くようにしているので、設定の際にはぜひ参考にしてください。

DBへの接続(database.yml)

以下のようなDBごとの接続設定をyamlファイルに複数定義することができます。 prompt_color はREPLのプロンプトに表示される文字色です。開発サーバーや本番サーバーで色を分けて注意を促すのに利用できます。

https://github.com/nogahighland/active_record_mysql_repl/blob/main/sample_config/.army.sample/databases.sample.yml

SSH Tunnelにも対応しており、bastionssh-user を設定することでSSH経由でDBに接続することができます。

AWS Session Managerを利用してローカルからリモートのDBに接続する場合は、すでにポートフォワーディングされているので、ローカル(127.0.0.1)のポートを指定するだけで接続できます。

ここで定義したDB名は、別途用意したzsh補完(後述)を設定してもらうと army コマンドの引数として補完されるようになります。

アソシエーション(association.yml)

ActiveRecordでいうアソシエーションとは、よく「リレーション」と言われるもので、テーブル同士の関連性を定義するものです。

基本的にはActiveRecordMysqlReplはDBに存在するテーブルカラム名に基づいて自動的にテーブル同士の belongs_to has_many の関連付けるようにしていますが、以下のケースはテーブルから明示的に読み取れないので定義する必要があります。

  • カラム名から明示的ではない関連性(例: profile_iduser_profiles テーブルのidを参照している場合 )
  • xxxx_id が他テーブルを参照しない

拡張機能(extensions/*.rb)

テーブルによってはアソシエーションだけでは実現できない振る舞いを定義したい場合もあるかもしれないので、利用者が自由に拡張機能を定義できるようにしています。
例えば以下の例では UserProfile オブジェクトに upcase_name というメソッドを追加しています。

https://github.com/nogahighland/active_record_mysql_repl/blob/main/sample_config/.army.sample/extensions/hello.rb

その他にも、Rubyのメタプログラミングを使用してグローバルメソッドを定義したり拡張スクリプト側でアソシエーションやhookを定義したりと、とにかく自由に拡張できるようにしています。利用方法は自由ですが、あくまでDB閲覧や操作の補助ツールなので、ここにアプリケーションとは異なるビジネスロジックが混入しないように注意してください。

pryrc

REPLに使用しているPryですが、多くのカスタマイズ項目が存在します。

https://github.com/pry/pry/blob/master/lib/pry/config.rb

army を使用する際に限り行うカスタマイズを指定することができます。例えば、以下ではコマンドの戻り値のオブジェクトを awesome_print で綺麗に表示し、ページャーで表示するようにしています。

https://github.com/nogahighland/active_record_mysql_repl/blob/main/sample_config/.army.sample/.pryrc.sample

ERD出力

RailsERD を使用してER図を出力することができます。

$ army [-c /path/to/.army.yml] -d <database> -e erd

以下のようなER図が出力されます。

zsh補完

以下のスクリプトでコマンド補完できるようにしています。都度実行するか、 ~/.zshrc に追記してください👍

$ eval "$(army --zsh-completion)"

その他、ビルトイン拡張

.XXX はクラスメソッド、#xxx はインスタンスメソッドです。

  • テーブル定義系: .d .ddl
  • 文字列やArrayに動的メソッド生やしてselectできる系: "value".{table名} "value".{table名}_by_{カラム名}
  • JSON系 #j #jp
  • クリップボード系: #cp
  • 表示系: #tabulate #csv
  • トランザクションのショートハンド: transaction { ... }
    • ActiveRecord::Base.connection.select_allexec_sql
  • 生SQL実行のショートハンド: exec_sql
    • ActiveRecord::Base.transactiontransaction

ActiveRecordネイティブの機能

とにかく便利な機能がめちゃくちゃあり、全てはここでは網羅できないので、以下のリンクを参考にしてください。

https://railsguides.jp/active_record_basics.html

まとめ

今回は、RubyのActiveRecordでMySQLにSSH接続してREPL操作できるRubyGemをご紹介しました。ぜひ、便利に使って頂ければ幸いです。
問題や改善のご要望があればGitHubにてレポートしていただいたり、Pull Requestを送っていただけると何よりです!

Appendix

RubyGemを作成するのに使用した参考文献

GitHubで編集を提案
Finatext Tech Blog

Discussion