Having your plugins and eating them too...

Liquid error: undefined method `login' for nil:NilClass : June 11th, 2006

Let's face it, rails plugins are a great way of making rails uniquely your own. And since full blown components are going the way of the dodo, wouldn't it be nice to be able to use controllers, models, views and helpers in a plugin without any other dependencies? Well after spending a bunch of time trying to figure out how to do it, it turns out its only 4 lines of code. Now this won't let you over-ride things in your main app or any other snazzy stuff like that. But I don't need that,. I just want to have a little mvc stack in my plugins sometimes. So for this to work, just add these four lines into the init.rb of a fresh plugin.
config.controller_paths << File.join(directory, 'app', 'controllers')
$LOAD_PATH << File.join(directory, 'app', 'controllers')
$LOAD_PATH << File.join(directory, 'app', 'models')
$LOAD_PATH << File.join(directory, 'app', 'helpers')
Then you can make an app/ directory in the root dir of the plugin with a directory for controllers, helpers, models and views inside. The way this works is that the config and directory local variables are automatically available to any plugin. The config var is the same as the Rails::Initializer.run do |config| block inside environment.rb in your main app. This just allows you to tack on more config stuff from a plugin. And the directory var is available and points to the root directory of your plugin. So we are just puting out little app/ dir into the load path in the proper way and it just works. I also usually make a symlink inside public in my main app that points to a dir in my plugin so I can have images and assetts. Also you need to add one line to the bottom of each of your controllers in order to set their template root. So if you have a FooController you need to put the following line after the class definition:
FooController.template_root = File.join(File.dirname(__FILE__), '..', 'views')

18 Responses to “Having your plugins and eating them too...”

  1. James Adam Says:
    Nice work! It's worth pointing out that this isn't quite the same as the functionality that components have/had (which closer to partials with dedicated controller logic than an MVC stack), but still, this is definitely neat. And who needs components anyway? :) One other minor thing to consider is that adding paths to the top of $LOAD_PATH might make your development mocks harder to load. You could try some variation of this instead, if you had any issues:
      # add the paths after /components
      index = $LOAD_PATH.index($LOAD_PATH.find { |p| p =~ /\/components$/ }) + 1
      $LOAD_PATH.insert(index, *%w{controllers models helpers}.collect { |d| 
        File.join(directory, 'app', d)
      })
    
  2. Scott Walter Says:
    Awesome! But how can I setup a route from the plugin?
  3. procreate Says:
    Ezra rocks!
  4. twifkak Says:
    Woah... wait, let's coin a term for doing this... like... Engines. Rawk.
  5. Loukas Says:

    Sorry :(

  6. Martinos Says:

    Nice

  7. Spyridon Says:

    Nice…

  8. Loukianos Says:

    Nice!

  9. Bikos Says:

    Cool…

  10. Vasileios Says:

    Cool!

  11. Vassilis Says:

    Sorry :(

  12. Timotheos Says:

    Cool.

  13. Drymiotes Says:

    Sorry :(

  14. Koinos Says:

    Interesting…

  15. Stratis Says:

    Cool.

  16. Stylianos Says:

    Interesting…

  17. Yanni Says:

    Nice!

  18. Demetri Says:

    Cool!

Sorry, comments are closed for this article.