Err the Blog Atom Feed Icon
Err the Blog
Rubyisms and Railities
  • “Real Console Helpers”
    – Chris on December 11, 2006

    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.

  • atmos, about 11 hours later:

    errtheblog saves the day again.

  • matz, 1 day later:

    We kicked hard and shout possibility, to add this feature which is oneself. Haxxers reads. The rails system console shakes.

  • Borobal, 6 days later:

    for the rails errtheblog much success

  • manik, 18 days later:

    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

  • Joshua Warchol, 22 days later:

    The pastie URL has changed. Try

    curl -0 http://pastie.caboo.se/27125.txt >> ~/.irbrc

  • Five people have commented.
    Chime in.
    Sorry, no more comments :(
This is Err, the weblog of PJ Hyett and Chris Wanstrath.
All original content copyright ©2006-2008 the aforementioned.