crabgrass mods v. 4 - v. 5 series

crabgrass plugins: mods and tools and engines oh my.

Terminology

  • plugins: a core feature of rails to allow for modifications to the behavior of your app or to rails. All plugins live in vendor/plugins. Plugins are intended to be useful for any rails application.
  • engines: these are super plugins, made available via the ‘engines’ plugin. The key difference is that engines can be entire web applications, with their own app directory. Like regular plugins, engines live in vendor/plugins. Engines are intended to add complex functionality to any rails application. The main application can override selective views and controller actions in a engines plugin.
  • inverted engines: the engines plugin that crabgrass uses has been inverted. Instead of allowing the main application to override what is in the plugins, the plugins are allowed to overide code in the main application. Inverted engines are the basis for tools and mods.
  • tools: these are crabgrass specific engines that are exclusively for creating new page types. For example, the WikiPage is a tool in tools/wiki_tool. All tools live in the directory tools. Tools are only meaningful for crabgrass. Every tool is really its own little mini-app, with its own controller, helper, model, and views.
  • mods: these are crabgrass specific engines, with the added ability to replace the views in app/views with the views in mods/modname/app/views. Modes live in the directory mods. Mods directly modify the behavior of crabgrass: they are not useful for any other rails application.

All the Rails Engines docs apply to tools and mods.

Configuration

Mods may be enabled or disabled by editing config/mods_enabled.list. Likewise for tools with config/tools_enabled.list.

Additionally, your mod may need extra routes. An example might be:

codetitle. config/routes.rb

  map.from_plugin :gibberize

See the mod README to find out if a routes entry is required.

Tools can be made visible or hidden on a per site basis. See config/sites.yml.

Creating mod or tool

Every crabgrass mod/tool starts out life as a regular plugin. To create a skeleton:

./script/generate plugin your_plugin_name

This will create a new plugin in your vendor/plugins directory.

Move this directory to mods or tools directory:

mv vendor/plugin/your_plugin_name mods

The first thing to do is edit your new mod’s init.rb:

self.override_views = true
self.load_once = false

If override_views is set to true, then view files in your mod will override those in the main app. If load_once is set to false, then you can make changes to your mod in development mod and see those changes reflected in the application without needing to restart script/server.

As with every engine, mods and tools may contain an ‘app’ subfolder. This app folder mirrors the app in the rails root. Files in the mod’s app will append or overwrite the files in the main app folder.

For example:

app
|-- controllers
|   |-- account_controller.rb
|   '-- application.rb
'-- views
    '-- account
        |-- index.html.erb
        '-- login.html.erb
mods
|-- mymod1
|-- mymod2
'-- mymod3
    '-- app
        |-- controllers
        |   '-- account_controller.rb
        '-- views
            '-- account
                '-- login.html.erb

The file mods/mymod3/app/views/account/login.html.erb will override app/views/account/login.html.erb (but only if override_views is set to true). The file mods/mymod3/app/controllers/account_controller.rb will add new methods or change existing methods of app/controllers/account_controller.rb.

finalize

Another thing that mods can do is to run some code after everything else has been run. This is not so useful for plugins, but for mods it is often needed: Suppose, for example, you want to extend the Page class. Normally, plugins are not written to know anything about your particular rails application, but in the case of mods they are intended to modify a very specific rails application.

If we were to try to modify the Page class in the init.rb of our mod, we would create many errors trying to reference Page too early in rail’s startup process.

To get around this, mods can pass a block to self.finalize and this code will only get called once everything is loaded.

For example:

codetitle. mods/mymode/init.rb

self.finalize do
  Page.class_eval do
    acts_as_rateable
  end
end

mod migrations

If your plugin requires database migrations, you can generate new migrations and put them in a db/migrate folder in the plugin.

Then, to add these migrations to the main rails app, you run this:

./script/generate plugin_migration

That will generate a new app level migration that will run your plugin migrations.

mod assets

If you want to distribute stylesheets/javascripts/images with your plugin put them in a stylesheets/javascripts/images folder inside an assets folder in the plugin. Next time you run script/console or start the server the folders inside your plugin assets folder will be copied to public/plugin_assets/plugin_name.

 

Models can be overridden, but it requires copying the entire model file into the plugin directory. In other words, you can’t selectively override parts of a model, but only the whole thing.

Helpers can be overriden in the same way as controllers and views. Rake tasks can be defined in the normal plugin fashion, in the tasks/ directory.

A very handy task for engines would notify if any code that had be overridden by the plugin had changed in trunk. Of course this wouldn’t catch every conflict, but would be helpful for diagnosing test errors and generally keeping an eye on things.

 
 

you can now selectively modify and overrider parts of models with apply_mixin_to_model(). See mods/README.

 
 

pietro: i think the mod assets section should be put into the readme, wikis are going the way of the dodo for howto / readme content for the code.

 
 

we actually have a doc for mods and one for tools i’ll try to create a generic doc about plugins and then link the mods and tools docs in it.

 
   

i tried to add the contents of this page to the repo and improve the plugins docs on commit 582a9d65. i’m tagging this page for deletion.