Toward a Swankier Rails Console
As Rails developers, we spend a fair amount of time in the Rails console, which is itself just the native Interactive Ruby Shell (IRB). By default, it’s not particularly pretty…
$ rails c
irb(main):001:0> def hello
irb(main):002:1> puts “hello”
irb(main):003:1> end
=> :hello
irb(main):004:0> hello
hello
=> nil
irb(main):005:0>
…but it gets the job done. We were content with it, because we didn’t know things could be better.
But then we started worrying. Our app lives on Heroku, and there are several other Heroku “forked” apps that give us non-production environments for various levels of testing. And with many shells open at once, it could be possible to accidentally run code against our production database that was intended for casual testing with fake data. (We have code reviews for scripts that modify production data, but what if the script was only ever supposed to be run locally?) The fact that we hadn’t yet made that sort of mistake wasn’t particularly reassuring.
Then we discovered .irbrc files, the Ruby config files for the IRB shell. Our first move was to add a visual indicator of the current Rails environment (click that link for more information on these options):
# Prepend the environment name to each line of the prompt.
rails_env = Rails.env.capitalizeIRB.conf[:PROMPT][:RAILS_ENV] = {
PROMPT_I: "#{rails_env} (%m):%03n:%i> ",
PROMPT_N: "#{rails_env} (%m):%03n:%i> ",
PROMPT_S: "#{rails_env} (%m):%03n:%i%l ",
PROMPT_C: "#{rails_env} (%m):%03n:%i* ",
RETURN: "=> %sn"
}IRB.conf[:PROMPT_MODE] = :RAILS_ENV
Which gave us the environment name on every line:
$ heroku run rails c -app my-development-app
Development (main):001:0> def hello
Development (main):002:1> puts “hello”
Development (main):003:1> end
=> :hello
Development (main):004:0>
This was helpful, but we found the production shell wasn’t quite alarming enough. So we gave it a little more oomph:
# Prepend the environment name to each line of the prompt.
rails_env = Rails.env# Add extra visual warning (caps, bold, red font) when in
# production.
if rails_env.production?
require "colorize"
display_rails_env = rails_env.upcase.colorize(:red).bold
else
display_rails_env = rails_env.capitalize
endIRB.conf[:PROMPT][:RAILS_ENV] = {
PROMPT_I: "#{display_rails_env} (%m):%03n:%i> ",
PROMPT_N: "#{display_rails_env} (%m):%03n:%i> ",
PROMPT_S: "#{display_rails_env} (%m):%03n:%i%l ",
PROMPT_C: "#{display_rails_env} (%m):%03n:%i* ",
RETURN: "=> %sn"
}IRB.conf[:PROMPT_MODE] = :RAILS_ENV
Which gives us:
$ heroku run rails c -app my-production-app
PRODUCTION (main):001:0>
And for other environments:
$ heroku run rails c -app my-development-app
Development (main):001:0>
Much better. This helps us to avoid accidentally running the wrong code in production, but what about double-checking our code in production? After all, sometimes we do need to run scripts against our live database (for instance, for zero-downtime schema changes). We’ve adopted a practice that’s become enormously helpful for us in these scenarios. First, the IRB change:
Then, how we use it in our scripts:
def destroy_test_students
confirm do
students_to_destroy = Student.where(name: "TEST")
puts "Destroying #{students_to_destroy.length} test students."
students_to_destroy.destroy_all
end
end
Giving us:
PRODUCTION (main):001:0> destroy_test_students
Destroying 904 test students.Confirm changes? [y/N] Whoops! I was expecting to destroy only two students. Time to investigate instead of committing this transaction.
No changes made.
PRODUCTION (main):002:0>
Running our changes in transactions allows us to roll them back safely, either by not confirming at the prompt or by raising an error at any point inside the block if something seems off (for instance, with a check like raise “Stop!” if students_to_destroy.length != 2
). This lets us feel much more confident about the changes we’re making to live data.
Lastly, there’s lots of room to improve IRB’s visuals, for instance with auto-indentation (IRB.conf[:AUTO_INDENT] = true
), syntax coloring, and whatever else you like. Here’s our entire file (so far):
Let us know if you find this useful, and we’d love to hear your own .irbrc tips and tricks!
Want to see how we’ve continued to improve .irbrc
since we wrote this? We’re hiring!