Ruby나 Rails 콘솔을 실행하는 방법은 다양합니다. irb, bundle exec irb, bundle console, rails console이 가장 흔히 쓰이는 명령어죠. 겉보기에는 비슷하지만, 실제로는 각각 동작 방식이 조금씩 다릅니다.
이 차이점을 모르면 여러 가지 문제에 부딪히게 됩니다. ActiveRecord 모델이 데이터베이스에 연결되지 않거나, 파일을 require했는데 엉뚱한 버전이 로드되거나, 당연히 쓸 수 있을 거라 생각했던 라이브러리가 존재하지 않는 경우가 생기죠.
그렇다면 어떻게 하면 상황에 맞는 올바른 콘솔을 선택할 수 있을까요?
Bundler vs non-Bundler
irb는 그저 순수한 Ruby 콘솔입니다. Gemfile을 전혀 신경 쓰지 않으며, Ruby 코어 라이브러리 외에는 아무것도 로드하지 않습니다. 그 외에 필요한 것은 모두 직접 require해야 합니다.
gem install로 설치한 젬이라면 irb 안에서 require할 수 있습니다. 반면 bundle install로 설치했다면 경우에 따라 require가 가능할 수도 있습니다. Bundler가 젬을 어디에 설치했느냐에 달려 있기 때문입니다. (bundle install --path나 bundle install --deployment처럼 실행하면 Bundler가 RubyGems의 젬 경로 밖에 젬을 설치하기도 합니다.)
irb는 Gemfile을 무시하기 때문에 Gemfile.lock에 적힌 버전도 전혀 중요하지 않습니다. irb는 시스템에서 찾을 수 있는 가장 최신 버전의 젬을 로드합니다:
~/Source/testapps/consoles[master *] jweiss$ gem list rails
*** LOCAL GEMS ***
rails (4.2.0.beta2, 4.2.0.beta1, 4.1.5, 4.1.1)
~/Source/testapps/consoles jweiss$ cat Gemfile | grep rails
gem 'rails', '4.1.5'
~/Source/testapps/consoles jweiss$ irb
irb(main):001:0> require 'rails'
=> true
irb(main):002:0> Rails.version
=> "4.2.0.beta2"
예상하지 못한 상황이라면 코드에서 정말 기괴한 문제를 일으킬 수 있습니다.
Ruby 코어 파일을 가볍게 실험해 볼 때는 irb가 좋은 선택입니다. 빠르고 별도의 설정도 필요 없으니까요.
하지만 콘솔을 실행하면서 Gemfile까지 활용하고 싶다면 대신 bundle exec irb를 실행하세요. bundle exec를 붙이면 irb가 Bundler가 인식하는 젬들만, 그리고 오직 그 젬들만 로드할 수 있게 됩니다:
~/Source/testapps/consoles jweiss$ bundle exec irb
irb(main):001:0> require 'rails'
=> true
irb(main):002:0> Rails.version
=> "4.1.5"
원하던 Rails 버전을 정확히 얻었습니다.
bundler/setup vs Bundler.require
그렇다면 언제 bundle exec irb 대신 bundle console을 실행해야 할까요?
bundle exec irb는 Gemfile.lock에 명시된 젬만 require할 수 있도록 환경을 준비해 줍니다.
bundle console은 한 단계 더 나아갑니다. bundle console을 실행하면 Gemfile에 있는 젬을 일일이 require할 필요조차 없습니다. 이미 자동으로 require되어 있기 때문이죠:
~/Source/testapps/consoles jweiss$ bundle exec irb
irb(main):001:0> Rails.version
NameError: uninitialized constant Rails
from (irb):1
from /usr/local/bin/irb:11:in `<main>'
~/Source/testapps/consoles jweiss$ bundle console
irb(main):001:0> Rails.version
=> "4.1.5"
bundle exec irb 콘솔 안에서 직접 Bundler.require를 호출해도 같은 효과를 얻을 수 있습니다. Gemfile에 있는 젬 중 require: false로 표시되지 않은 것들은 모두 자동으로 require되어, 추가 작업 없이 바로 사용할 수 있습니다. Gemfile을 사용하는 프로젝트에서 작업할 때는 정말 편리한 기능입니다.
Rails 접근하기
아직 하나 더 살펴볼 차이가 남아 있습니다. 바로 bundle console과 rails console의 차이입니다.
~/Source/testapps/consoles jweiss$ bundle console
irb(main):001:0> Rails.application
=> nil
~/Source/testapps/consoles jweiss$ rails console
Loading development environment (Rails 4.1.5)
irb(main):001:0> Rails.application
=> #<Consoles::Application:0x007f8db4d5ab30 @_all_autoload_paths=["/Users/jweiss...
bundle console은 그저 젬들을 require할 뿐입니다. rails console은 젬을 require하는 데서 끝나지 않고, Rails 환경 전체를 로드하고 오토로딩을 설정하고 애플리케이션을 초기화하여, 온전한 Rails 환경을 그대로 제공합니다.
bundle console에서도 config/environment.rb를 require하면 Rails 콘솔과 유사한 환경을 만들 수 있습니다:
~/Source/testapps/consoles jweiss$ bundle console
irb(main):001:0> Rails.application
=> nil
irb(main):002:0> require_relative 'config/environment.rb'
=> true
irb(main):003:0> Rails.application
=> #<Consoles::Application:0x007fd264f0b7c8 @_all_autoload_paths=["/Users/jweiss...
정리: 한 단계씩 더 복잡해지는 네 가지 콘솔
내용을 요약해 보겠습니다.
irb는 가장 기본적인 Ruby 콘솔입니다.Gemfile을 무시하며, require하지 않으면 Ruby 코어 클래스만 사용할 수 있습니다. Bundler가 RubyGems 로드 경로 밖에 설치한 젬은 쉽게 불러올 수 없습니다.bundle exec irb는irb에bundler/setup을 require한 것과 같습니다.Gemfile.lock에 있는 젬만 손쉽게 require할 수 있지만, Bundler가 설치한 위치와 관계없이 해당 젬들을 로드할 수 있습니다.bundle console은bundle exec irb에서Bundler.require까지 호출한 것과 같습니다.Gemfile의 젬 중require: false로 표시된 것을 제외하면 require 없이 바로 사용할 수 있습니다. 직접 젬을 개발하거나 Rails가 아닌 프로젝트를 진행할 때 특히 유용합니다.rails console은 Rails 앱 안에서bundle console을 실행한 뒤config/environment.rb까지 require한 것과 같습니다. Rails 앱 전체를 자유롭게 다룰 수 있고, 오토로드와 데이터베이스 연결도 모두 정상 동작하며, 모든 구성 요소가 기대한 대로 연결됩니다. Rails 앱에서 작업한다면 이것이 가장 유용한 콘솔입니다.
네 콘솔 사이의 차이는 크지 않습니다. 대부분은 "아, 이 파일이 require 안 됐네? require하면 되겠네!" 정도의 사소한 수준이지만, 원인을 모르는 상태에서 마주치면 완전히 짜증나는 문제가 되기도 합니다. (대체 왜 RAKE 잘못된 버전을 계속 불러오는 거야!?)
하지만 각 콘솔의 동작 원리를 이해하고 있다면, 상황에 맞는 올바른 콘솔을 적시에 선택할 수 있습니다. 그리고 필요한 라이브러리는 언제나 손이 닿는 곳에 있겠죠.