やりたいこと
Railsのとっても便利なコンソール。自社のサービス運用をしているところでは、本番のappサーバにsshでログインしてRailsコンソールを開いて、データをチョメチョメすることがありますよね。
でも、こんな不便もあります。
- sshでログインしてRailsコンソールを立ち上げるのが面倒
- Railsコンソールのリソース消費がサービス運用に影響する
1つ目は screen や byobu を使って回避できるところですが、そうすると2つ目の問題が肥大します。
インフラ管理担当から怒られることもあるでしょう。。
そんな時に「ローカル環境で立ち上げたRailsコンソールから、本番環境のDBを操作できたら便利なんじゃないかなぁ」と思って考えた便利な技です。
前提条件
- Railsでサービス構築/運用している
- ローカル環境から本番DBへの接続が可能
手順
以下全てローカル環境です。
database.ymlに本番やステージングDBへの接続を記述しておく
Railsの起動 environment と区別するため、ここではRailsデフォルトで用意されている production ではなく、 honban としています。
development:
adapter: mysql2
host: dev.db.server
database: app_name
username: [filtered]
password: [filtered]
test:
adapter: mysql2
host: dev.db.server
database: app_name<%= ENV['TEST_ENV_NUMBER']%>
username: [filtered]
password: [filtered]
# ここ!
honban:
adapter: mysql2
host: 127.0.0.1 # sshトンネリングの設定に合わせています
port: 13306 # sshトンネリングの設定に合わせています
database: app_name_production
username: [filtered]
password: [filtered]
Railsコンソールを立ち上げて(developmentでね)DBを切り換える
$ rails console
[1] pry(main)> # 開発環境DB
[2] pry(main)> User.count
(1.3ms) SELECT COUNT(*) FROM `users` WHERE `users`.`deleted_at` IS NULL
3
[3] pry(main)> # 本番DBに切り換え
[4] pry(main)> ActiveRecord::Base.establish_connection(:honban)
#<ActiveRecord::ConnectionAdapters::ConnectionPool:.......
[5] pry(main)> User.count
(17.0ms) SELECT COUNT(*) FROM `users` WHERE `users`.`deleted_at` IS NULL
343321
ポイントは [4]のこれです。
ActiveRecord::Base.establish_connection(:honban)
Rails.env はあくまでも deveploment のまま、DBだけ切り替えるんです。
切り換えは何度も出来るので、開発環境 > ステージング > 本番 を切り換えながらデータをチェックするなんてことも可能です。
ここが便利ね
development だけに適用しているgemが使える
起動を重くするような gem は、Gemfileで dvelopment, tes のスコープを切って本番環境ではロードしないのが常套かと思います。でもこのやり方だと、 development のみのgemが使えるんです。
上サンプルでも pry を使っているのが分かると思います。hirb も使えちゃいます。
本番環境から(少しだけ)データを持ってくるのが簡単
接続環境を切り替えられるので、こんなことも可能です。
$ rails console
Loading development environment (Rails 3.2.14)
Frame number: 0/4
[1] pry(main)> # 本番環境に接続
[2] pry(main)> ActiveRecord::Base.establish_connection(:honban)
#<ActiveRecord::ConnectionAdapters::ConnectionPool:....
[3] pry(main)> user = User.last
User Load (7.4ms) SELECT `users`.* FROM `users` WHERE ......
+----+------------+------------+.....
| id | email | encrypt... |
+----+------------+------------+.....
| 51 | hoge@ex... | $2a$10$... |
+----+------------+------------+.....
1 row in set
[4] pry(main)> copied_user = user.dup
+------------+------------+----------
| email | encrypt... | reset_pa.
+------------+------------+----------
| hoge@ex... | $2a$10$... |
+------------+------------+----------
1 row in set
[5] pry(main)> # 開発環境に接続し直し
[6] pry(main)> ActiveRecord::Base.establish_connection(:development)
#<ActiveRecord::ConnectionAdapters::ConnectionPool:....
[7] pry(main)> copied_user.save validate:false #開発環境に保存
(1.3ms) BEGIN
SQL (2.2ms) INSERT INTO `users` (`........
(2.9ms) COMMIT
true
※データの転送量を考えてちょっとずつ分けてやりましょーね。