Gavin Kistner
2005-Apr-17 04:03 UTC
[Tip] Introspection to determine all the controllers/actions available.
I am setting up a site with ACL style permissions. Each role will be
granted permission to one or more of the actions throughout the site.
Rather than hard-coding the list of controllers and actions into the
DB, I thought it would be nice to have the system figure out what
controllers and actions would be available dynamically, so I''m sure not
to miss any.
Following is the code I wrote. Each Act in the acts table holds the
path to a controller/action (I couldn''t call the model
"Action" because
of name collision with rails), and is joined in a
has_and_belongs_to_many relationship with the Roles table.
Mostly I''m supplying this code for others who might want to do the same
thing, but I''d also appreciate feedback on the code. Oh! and also, how
might I cause this code to run ''once'' as rails starts up,
rather than
having to manually invoke it each time the admin page that uses it is
called.
class Act < ActiveRecord::Base
has_and_belongs_to_many :roles
# Ensure that the table has one entry for each controller/action pair
def self.synchronize_with_controllers
# Load all the controller files
# ToDo: hunt sub-directories
Find.find( RAILS_ROOT + ''app/controllers'' ) do
|file_name|
require file_name if /_controller.rb$/ =~ file_name
end
# Find the actions in each of the controllers,
# resulting in an array of strings named like "Foo/bar"
# representing the controller/action
all_actions = ObjectSpace.subclasses_of( ApplicationController
).collect do |controller|
controller.action_methods.collect do |method_name|
controller.name.gsub( /Controller$/, '''' ) +
''/'' + method_name
end
end.flatten!
# Find all the ''action_path'' columns currently in my
table
all_records = self.find_all
known_actions = all_records.collect{ |row| row.action_path }
# If controllers/actions exist that aren''t in the db
# then add new entries for them
missing_from_db = all_actions - known_actions
missing_from_db.each do |action_path|
self.new( :action_path => action_path ).save
end
# Clear out any entries in the table that do not
# correspond to an existing controller/action
bogus_db_actions = known_actions - all_actions
unless bogus_db_actions.empty?
#Create a mapping of path->Act instance for quick deletion lookup
records_by_action_path = { }
all_records.each{ |row| records_by_action_path[ row.action_path ]
= row }
bogus_db_actions.each do |action_path|
records_by_action_path[ action_path ].destroy
end
end
end
end
--
(-, /\ \/ / /\/