I have a plugin-based system that I use for application development in Rails. Each plugin implements an engine with MVC components, etc. The main application is simply an empty harness that delegates all the work to the plugins that are installed.
I'm currently upgrading to Rails 3.1 from Rails 2.3.5, and am trying to get the asset pipeline working with my framework.
The problem I'm having is trying to programmatically require my plugin's assets into, for example, the application.js manifest.
I can manually add them like so:
//= require <plugin_manifest_path>
And everything works as expected. However, as there are dozens of plugins in my framework, and each installation has a different mix, I want to have this manifest change based on which plugins are installed. I tried this as a solution:
<%=
Rails.plugins.collect do |plugin|
"//= require #{plugin}"
end.join("\n")
%>
But what I discovered is that the require/directive phase of the asset pipeline compilation happens before ERB expansion, so the generated comments were simply ending up as comments.
Is there another mechanism for including paths for compilation that might work? Any way to pre-process a manifest file before the directive processing kicks in?
If I can't think of anything better, I may have to write a rake/deployment task that generates a plugin.js manifest file on deploy, but I'd love something more clear and elegant if possible. Thanks!
EDIT: Solution found, will post full solution as soon as stackoverflow lets me. See comments below in the mean time...
OK, so here's the solution:
Internally, the asset pipeline (aka Sprockets) require directive calls context.require_asset()
to actually require whatever path is specified in the directive. Turns out, that means that the require_asset
method is present and available during ERB expansion. So, the correct solution was:
// ... Standard application.js stuff here ...
//= require_tree .
<%
Rails.plugins.each do |plugin|
require_asset(plugin.to_s)
end
%>
Added that in, and all worked as expected. Whew!
In case you're wondering about that Rails.plugins
bit, I added an extension to the Rails module to get the actual list of plugins that are loaded, in load order, based on config.plugins. For completeness, here it is:
module Rails
def self.plugins
# Get sorted list of all installed plugins
all = Dir.glob(Rails.path('vendor/plugins/*/init.rb')).collect {|p| p.extract(/\/([^\/]+)\/init.rb$/) }
all.sort!
all.collect! {|p| p.to_sym }
# Get our load order specification
load_order = Rails.application.config.plugins
# Split the load order out, and re-assemble replacing the :all keyword with the
# set of plugins not in head or tail
head, tail = load_order.split(:all)
all -= head
all -= tail
# All set!
head + all + tail
end
end
And the final detail was creating a <plugin_name>.js
manifest file in each plugin's app/assets/javascripts directory.
Hope that helps someone!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With