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 -- (-, /\ \/ / /\/