You might recall I’m somewhat fond of irb and the Rails console. We all have our weaknesses. The console is a real life changer, but (and there’s always a but) recently I’ve been running into the same issue again and again: there’s no custom helper love in the Rails console. What gives?
We could kick and scream, or we could add this feature in ourselves. Screamers may now take leave. Haxxers may continue reading.
Application Helpers
Okay, here’s my ApplicationHelper module. I worship brevity.
module ApplicationHelper def application_helper_method true end end
How do I access that method in the console?
>> helper.application_helper_method NoMethodError: undefined method `application_helper_method' for #<Object:0x2572f68> from (irb):1
Failure. But, let’s think about this. It’s just Ruby, right? If we think back to our studies, we may remember the extend method. From the Pickaxe: “The Object#extend method adds the methods in its parameter to its receiver.” Erm, right. So we can add the methods from our target to our receiver. Let’s add the methods from ApplicationHelper to helper then, yes?
>> helper.extend ApplicationHelper => #<Object:0x2572f68> >> helper.application_helper_method => true
Glory be to the ships at sea. That’s it, there’s nothing else in this post. But stick around if you want some evil and esoteric Rubyin’.
Generification
I play with my methods in the console all the time, so I need to wrap this up. I like the way the helper method works in controllers, so I’ma copy that.
The current helper implementation for the console:
def helper @helper_proxy ||= Object.new end
Later, helpers from ActionView are added. But that’s not important. Like I said, I want to be able to do helper :application (controller-style) to load up my ApplicationHelper.
def helper(*helper_names) returning @helper_proxy ||= Object.new do |helper| helper_names.each do |h| helper.extend "#{h}_helper".classify.constantize end end end
And we’re there. That make sense? See Quickly: returning if you need a hint.
Now:
>> helper :application => #<Object:0x2572f68 ... > >> helper.application_helper_method => true
Also valid: helper :application, :posts (to load more than one at a time). Nice.
Take It With You
Where does this go? Well, I’ve put in a Rails patch to try and slip it into core. Wouldn’t that be cool? The patch even tries to auto-load ApplicationHelper on startup.
In the meantime, I’ve got this little number in my .irbrc:
def Object.method_added(method) return super(method) unless method == :helper (class<<self;self;end).send(:remove_method, :method_added) def helper(*helper_names) returning $helper_proxy ||= Object.new do |helper| helper_names.each { |h| helper.extend "#{h}_helper".classify.constantize } end end helper.instance_variable_set("@controller", ActionController::Integration::Session.new) def helper.method_missing(method, *args, &block) @controller.send(method, *args, &block) if @controller && method.to_s =~ /_path$|_url$/ end helper :application rescue nil end if ENV['RAILS_ENV']
Install it with: curl -0 http://pastie.caboo.se/27125.txt >> ~/.irbrc
When I startup script/console, the default helper is (evily) overriden with my new&somewhatimproved version.
But wait, what’s that other code?
But wait, what’s that other code? Mostly it’s from another patch, this one. It lets us use helper.link_to.
Stock console:
>> helper.link_to 'home', :controller => 'static', :action => 'splash' NoMethodError: You have a nil object when you didn't expect it!
With the patch:
>> helper.link_to 'Bones', :controller => 'users', :action => 'show', :id => 1 => "<a href=\"/users/1\">Bones</a>"
It also gives us *_path and *_url methods on helper, which are just a nicety (they’re already available on the console’s app method).
Before:
>> helper.user_path 1 NoMethodError: undefined method `user_path' for #<Object:0x256f6d8>
After:
>> helper.user_path 1 => "/users/1"
Definitely helps if your helpers call any named route or RESTful route helpers. Definitely.
Further Goodness
In case you missed it, San Francisco Rubyist Konstantin Gredeskoul wrote about loading session objects into the console recently. Then there’s this wirble thing everyone is talking about.
Also, Ben Bleything made a post just today on tracing method execution in irb. Yum. irb.
Update: Fixed some typos. Nothing to see here.
errtheblog saves the day again.
We kicked hard and shout possibility, to add this feature which is oneself. Haxxers reads. The rails system console shakes.
for the rails errtheblog much success
Isn’t there a small typo in there. bq.Like I said, I want to be able to do helper :application (controller-style) to load up my ApplicationController.
Shouldn’t it be load up my ApplicationHelper
The pastie URL has changed. Try
curl -0 http://pastie.caboo.se/27125.txt >> ~/.irbrc
Chime in.