PIYO - Tech & Life -

デプロイ先のサーバーでrails consoleできないときの対応とCapistranoからの使い方

AWS Ruby Rails

RailsアプリケーションをCapistranoでデプロイするのはよくあるやり方です。僕もその方法でサービスをデプロイしています。 ところがこの方法でデプロイしたサーバーではrails consoleがうまく動かないという問題(もしくは僕の設定不備)があることがわかりました。

Railsのルートに居るにも関わらずUsageがプリントされるだけで終わってしまうのです。

$ cd /home/deploy/app/app_name/current
$ bin/rails console
Usage:
  rails new APP_PATH [options]

Options:
  -r, [--ruby=PATH]              # Path to the Ruby binary of your choice

# 以下略

staging環境にしろproduction環境にしろ、ちょっとデータを見たかったりadmin権限をこっそり付与したりといったことはわりと多いので、rails consoleが使えないのはとても困ります。

そこでいつもお世話になっているQA@ITさんに質問を投げさせてもらいました。

AWSにデプロイしたRailsアプリケーションのコンソールを起動したいがUsageが出てしまう - QA@IT

[http://qa.atmarkit.co.jp/q/2925:image:large]

ですが、これといった回答は得られませんでした。仕方なくごまかしながら開発を進めていたのですが、ある時気がつきました。irbなりpryでRailsの環境をロードしてしまえばいいんだ!

rails console が動かない、効かない

そこでこんなスクリプトを書きましたよ。 必要なgemをrequireしてからRailsをロードし、最後にpryを実行します。

#!/usr/bin/env ruby

require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
  Pathname.new(__FILE__).realpath)

require 'rubygems'
require 'bundler/setup'

require File.expand_path('../application', __FILE__)
Rails.application.require_environment!

load Gem.bin_path('pry', 'pry')

そうしたらこんなふうに実行します。

$ cd /home/deploy/app/app_name/current
$ RAILS_ENV=production config/rails_console.rb # configに置くのはどうよと思いますが、まあいいんです。
[WARN] cannot load Rails console commands (Not on Rails2 or Rails3?)
[1] pry(main)> 

なんか警告が出ましたが、特に問題なく使えるので細かいことは気にしなくていいでしょう。

rails consoleコマンドが動かない理由をちゃんと解明していない気持ち悪さは残りますが、本番用サーバーでもrails console相当のことを実行できるようになってストレスを軽減できるようになりました。

Capistranoのタスクでリモートのconsoleを立ち上げる

先の方法ではSSHログイン後Railsのルートへ移動し、rails_console.rbスクリプトを叩いていました。大した手順じゃないですが面倒なのでCapistranoを使ってローカルのターミナルからダイレクトに接続してしまいましょう。

リモートのrails consoleを起動するためのタスクがこちらで紹介されているのでそれを流用しました。rails consoleのところをconfig/rails_console.rbにするだけですね。 Capistrano task to open a rails console on a remote server. Require this file in your deploy.rb and run “cap rails:console”

namespace :rails do
  task :console, :roles => :app do
    run_interactively "RAILS_ENV=#{rails_env.to_s.shellescape} #{latest_release.shellescape}/config/rails_console.rb"
  end
end

def run_interactively(command, server=nil)
  server ||= find_servers_for_task(current_task).first
  exec %Q(ssh #{server.host} -t 'sudo su - #{application} -c "cd #{current_path} && #{command}"')
end

run_interactivelyではsshでリモートのコマンドを実行するために実行したいコマンドに-tオプションを付与して実行しています。

これで、次のようなコマンドでconsoleにダイレクトに接続できストレスフリーです!

$ cap rails:console

$ cap production rails:console # multistageを使っている場合