I have a similar setting with audits where all of my resources have an
audit log. As this functionality cuts across the resources, I handle
display of the audit log by a separate controller. I haven't come up
with a way to do this neatly with map.resources, rather, I add the
routes like this
map.with_options(:controller => 'audits', :action => 'show') do |
audits_map|
audits_map.audits ':resources/:id/audits.:format'
audits_map.audits ':resources/:id/audits', :format => 'html'
end
The AuditsController looks (partially) like this
class AuditsController < ApplicationController
session :off, :if => proc { |req| req.parameters[:format] != 'html' }
def show
respond_to do |format|
format.html { show_html }
format.atom { show_atom }
format.xml { show_xml }
end
end
private
def show_html
setup_objects
render :action => 'show'
end
def setup_objects
audited_class = assert_valid_resource_name(params[:resources])
auditable_type = audited_class ?
audited_class.singularize.camelize : nil
auditable_id = params[:id]
@audits =
Audit.find_all_by_auditable_type_and_auditable_id(auditable_type,
auditable_id)
end
end
To ensure that audit logs can only be displayed for valid resources,
I've monkey patched resource route registration to collect resource
names and check against these names. Here, too, I'm all in favor of a
more elegant solution.
In ApplicationController
def assert_valid_resource_name(name)
raise ArgumentError, "Resource does not exist: #{name}" unless
ActionController::Resources.valid_resource?(name)
name
end
loaded on startup from a file in lib
ActionController::Resources.module_eval do
mattr_accessor :valid_resources
ActionController::Resources.valid_resources =
def self.valid_resource?(name) #:doc:
ActionController::Resources.valid_resources.include?(name.to_sym)
end
private
def map_resource_with_collecting(entities, *args, &block)
ActionController::Resources.valid_resources |= [ entities ]
map_resource_without_collecting(entities, *args, &block)
end
alias_method_chain :map_resource, :collecting
end
HTH,
Michael