#48 Console Tricks (revised)
- Download:
- source codeProject Files in Zip (46.7 KB)
- mp4Full Size H.264 Video (27 MB)
- m4vSmaller H.264 Video (11.5 MB)
- webmFull Size VP8 Video (10.8 MB)
- ogvFull Size Theora Video (23.5 MB)
The Rails console is an extremely useful tool and most Rails developers use it all the time for debugging or experimenting with code and also as an interface for modifying the application’s data. In this episode we’ll give you some tips on how to get the most out of the console.
The console can be opened from a terminal window by running rails console
, or the shorter alternative rails c
, in the application’s directory. We can pass a number of options to this command; some useful ones are production
, which will start the application in the production environment, and --sandbox
which will wrap the console session in a database transaction so that any modifications we make are rolled back. This second option is handy if we want to experiment with something without permanently changing the database.
$ rails c --sandbox Loading development environment in sandbox (Rails 3.2.3) Any modifications you make will be rolled back on exit 1.9.3-p125 :001 > Product.delete_all SQL (1.1ms) DELETE FROM "products" => 29 1.9.3-p125 :002 > exit (1.6ms) rollback transaction
Useful Console Methods
Rails provides some useful methods specifically for use in the console. One is app
, which is useful for interacting with our application. We can call URL helpers on this to see where a path routes to.
> app.products_path
=> "/products"
We can also make requests to our application by calling app.get
and passing in a path.
> app.get app.products_path Product Load (0.5ms) SELECT "products".* FROM "products" WHERE ("products"."released_at" <= '2012-06-18 19:42:47.116943' AND ("products"."discontinued_at" IS NULL OR "products"."discontinued_at" > '2012-06-18 19:42:47.116986') AND "products"."stock" >= 2 AND "products"."name" LIKE '%%') => 200
In this example the ProductsController
’s index
action is run. This is a great way of seeing what database queries are performed for a given request. The app method is an instance of ActionDispatch::Integration::Session
which is something normally used for integration testing but it works perfectly well in the console too.
If we look at the Rails Guide for integration testing we’ll see some more of the methods that we can call on app
. We can run app.cookies
to see which cookies are set, or use app.response.headers
and app.response.body
to see the headers or body of the last response. We can even inspect the instance variables that were assigned by the controller in the last request by calling assigns and passing in the variable’s name as a symbol.
> app.assigns(:products).size => 22
A similarly helpful method is helper
. This gives us access to the view context and we can execute helper methods on it to test them out.
> helper.number_to_currency(12.34) => "$12.34"
We can also call the custom helper methods that we define in our application. One thing that won’t work, though, is the params
hash so if we have a helper method that references the request parameters then calling it here will raise an exception. To fix this there’s another method that the console provides called controller
that returns a new ApplicationController
instance. For some reason this isn’t hooked up to the helper but we can set it manually, along with its parameters which will then be available to the helper.
> helper.controller = controller => #<ApplicationController:0x007fccc88ae0c0 @_routes=nil, @_action_has_layout=true, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_request=nil, @_response=nil> > controller.params = {foo: "bar"} => {:foo=>"bar"} > helper.params => {:foo=>"bar"}
Another useful console method is called reload!
. This picks up any changes we’ve made to our application since starting the console. Let’s say that the Product
model’s to_param
method isn’t working the way we want it to. We can make the necessary changes in the model file then run reload!
in the console. When we run to_param
on the product again the changes will have been picked up. This is a handy trick but it does have the occasional issue so if you want to be absolutely sure that the changes have been picked up it can be better to stop and restart the console.
Customizing The .irbrc File
Ever since Rails 3.1 ActiveRecord logs its SQL queries to the console which is very useful. If we want to disable this feature we can do so by setting the logger level to anything above zero.
> Product.count (0.3ms) SELECT COUNT(*) FROM "products" => 29 > ActiveRecord::Base.logger.level = 1 => 1 > Product.count => 29
To make this the default behaviour in the console we can set it in the .irbrc
file in our home directory. We can put any Ruby code into this file and it will be evaluated when either irb or the console are loaded. We have some code in this file already to enable tab completion and a save history feature that keeps up 1,000 lines of history between sessions.
#!/usr/bin/env ruby require 'irb/completion' require 'irb/ext/save-history' IRB.conf[:PROMPT_MODE] = :SIMPLE IRB.conf[:SAVE_HISTORY] = 1000 IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
We can customize this file to make it fit our preferences. To remove the SQL query logging we can can add a line like this:
ActiveRecord::Base.logger.level = 1 if defined? ActiveRecord::Base
When we start up a new console session now the SQL logging behaviour will be disabled by default. We won’t leave this line in, however, as the logging behaviour is useful.
We can also define methods in this file. If we want for example an easy way to display the YAML representation of objects we can define a y method, like this:
def y(obj) puts obj.to_yaml end
There used to be a method that did this but it’s been removed from recent versions of Rails. When we restart the console now we can use this method like any other.
>> y Product.first --- !ruby/object:Product attributes: id: 1 name: Settlers of Catan category_id: 2 price: 34.95 released_at: 2012-03-15 18:58:17.061596000 Z discontinued_at: stock: 5 created_at: 2012-06-09 18:58:17.075666000 Z updated_at: 2012-06-09 18:58:17.075666000 Z
The possibilities are almost endless here. We could even do something strange and define a mate
method on every object that will open up that method in TextMate.
class Object def mate(method_name) file, line = method(method_name).source_location `mate '#{file}' -l #{line}` end end
When we reopen the console now and run the code below, TextMate will open up the source code at the correct line.
>> helper.mate(:number_to_currency)
Gems That Work With irb
There are a lot of gems designed to work with irb. A good one is Hirb which will display ActiveRecord data in a table. We can install this gem in the usual way.
$ gem install hirb
If we open the console now and run require 'hirb'
this won’t work, however. This is because Bundler locks down the gems that we can use in our Rails app to those listed in the gemfile. We could add a reference to Hirb at the bottom of our app’s gemfile for just the development group but we’d have to do this for every Rails app that we want to use Hirb with. Also other developers working on the same project may not want this installed. This is something we want to add to our development environment rather than to specific applications. Thankfully there’s a hack we can add to our irbrc file that can help with this.
# Break out of the Bundler jail # from https://github.com/ConradIrwin/pry-debundle/blob/master/lib/pry-debundle.rb if defined? Bundler Gem.post_reset_hooks.reject! { |hook| hook.source_location.first =~ %r{/bundler/} } Gem::Specification.reset load 'rubygems/custom_require.rb' end
This resets the gem specifications without the Bundler hook. There don’t appear to be any side-effects from using this and it works well. If we require Hirb in the console now it will work.
>> require 'hirb' => true >> Hirb.enable => true >> Product.limit(5) Product Load (0.3ms) SELECT "products".* FROM "products" LIMIT 5 +----+---------+--------+--------+---------+--------+-------+--------+---------+ | id | name | cat... | price | rele... | dis... | stock | cre... | upda... | +----+---------+--------+--------+---------+--------+-------+--------+---------+ | 1 | Sett... | 2 | 34.95 | 2012... | | 5 | 201... | 2012... | | 2 | Red ... | 3 | 12.49 | 2012... | | 5 | 201... | 2012... | | 3 | Oak ... | 4 | 223.99 | 2012... | | 5 | 201... | 2012... | | 4 | Tech... | 2 | 27.99 | 2012... | | 5 | 201... | 2012... | | 5 | Oh's... | 5 | 3.95 | 2012... | | 5 | 201... | 2012... | +----+---------+--------+--------+---------+--------+-------+--------+---------+ 5 rows in set
If we want Hirb to always be available in the console we can do that by adding the following code.
if defined? Rails begin require 'hirb' Hirb.enable rescue LoadError end end
This checks to see if Rails is defined then requires and enables Hirb if so. Note that we rescue any LoadError
just incase we switch to another version of Ruby that doesn’t have the Hirb gem installed.
Other useful gems include Awesome Print, which gives us an ap method that will show models’ attributes nicely formatted and with colour. The Clipboard gem enables us to interact with the system’s clipboard by giving us Clipboard.copy and Clipboard.paste methods. MethodFinder is another handy gem that can help us if we know there’s a method that does something but can’t remember what it’s called. For example if we know that there’s a method on the String object that will return “ABC” when we pass it “abc” we can use MethodFinder to find it.
>> require 'methodfinder' => true >> "abc".find_method("ABC") => ["String#swapcase", "String#swapcase!", "String#upcase", "String#upcase!"]
FancyIrb is another good gem. This will display output results inline if they fit.
>> require 'fancy_irb' => true >> FancyIrb.start => "Enjoy your FancyIrb :)" >> 3 + 4 #=> 7
The Wirb gem will colourize output, too, if you want that. There’s a compilation of many of these utility gems called irbtools. Even if you don’t install this gem there’s a great list of other utility gems listed in its README.
Finally, we can’t finish without mentioning Pry. This is a replacement for irb with many extra features. It was covered in episode 280 and there’s much more information about it there.