Class: Controller
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Controller
- Defined in:
- app/models/controller.rb
Overview
the table is managed so as to make it mirror the file system the only reason this is necessary is to be able to store in the database a last_modified attribute for a file, in order to know whether the actions table is up to date for this controller or should be regenerated from the file contents The class represents both filesystem objects and database objects hmmm… is that really the best way to design it, shouldn’t it be two classes?
Constant Summary collapse
- CONTROLLERS_DIR =
"#{Rails.root.to_s}/app/controllers"
Class Method Summary collapse
- .all_actions_from_files ⇒ Object
-
.all_controller_names ⇒ Object
returns an array of strings, each one is a controller name.
- .all_files ⇒ Object
- .all_modified_files ⇒ Object
- .application_files ⇒ Object
- .engine_controller_paths ⇒ Object
- .engine_files ⇒ Object
-
.update_table ⇒ Object
updates the controllers table so that it contains a record for each controller file in the /app/controllers directory.
Instance Method Summary collapse
-
#action_list ⇒ Object
returns an array of arrays, each contains the controller controller_name and action name.
-
#actions_from_file ⇒ Object
the actions returned are those that were in the file when it was loaded this is reasonable only because the actions are changed by the developer and never get changed “on the fly”.
- #controller ⇒ Object
- #file ⇒ Object
- #file_modification_time ⇒ Object
- #model_name ⇒ Object
-
#modified? ⇒ Boolean
a file is declared to be modified if it’s either older or newer than the last_modified date this triggers re-parsing the actions in the file whether it’s older or newer and so responds both to the file being edited and also the database being restored from an older version.
Class Method Details
.all_actions_from_files ⇒ Object
97 98 99 |
# File 'app/models/controller.rb', line 97 def self.all_actions_from_files all_controller_names.inject([]){ |ar,c| ar+=c.action_list; ar } end |
.all_controller_names ⇒ Object
returns an array of strings, each one is a controller name
15 16 17 |
# File 'app/models/controller.rb', line 15 def self.all_controller_names @@controllers ||= all_files.map { |file| file.camelize.gsub(".rb","") } end |
.all_files ⇒ Object
19 20 21 |
# File 'app/models/controller.rb', line 19 def self.all_files application_files + engine_files end |
.all_modified_files ⇒ Object
47 48 49 |
# File 'app/models/controller.rb', line 47 def self.all_modified_files all_controller_names.select(&:modified?) end |
.application_files ⇒ Object
43 44 45 |
# File 'app/models/controller.rb', line 43 def self.application_files Dir.new(CONTROLLERS_DIR).entries.reject{|c| c.match(/^\./)}.reject{|c| c == 'application_controller.rb'} end |
.engine_controller_paths ⇒ Object
37 38 39 40 41 |
# File 'app/models/controller.rb', line 37 def self.engine_controller_paths Rails::Engine.subclasses.collect { |engine| engine.config.eager_load_paths.detect{|p| p=~/controller/} }.flatten.compact end |
.engine_files ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'app/models/controller.rb', line 23 def self.engine_files engine_controller_paths.inject([]) do |array, path| # entries may be controller files, but if there are namespaced controllers # then entries are directories directories, files = Dir.new(path).entries.reject{|c|c.match(/^\./)}.partition{|c| File.directory?(File.new(File.join(path,c)))} array += files directories.each do |directory| files = Dir.new(File.join(path,directory)).reject{|c|c.match(/^\./)}.entries.map{|file| File.join(directory,file)} array += files end array end end |
.update_table ⇒ Object
updates the controllers table so that it contains a record for each controller file in the /app/controllers directory
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'app/models/controller.rb', line 75 def self.update_table cc = Controller.all.inject({}){ |hash,controller| hash[controller.controller_name]=controller; hash } # from the database all_controller_names.each do |f| # f is of the form "ItemsController" cont = f.tableize.gsub!("_controllers","") # cont is of the form "items" admin_name = Role.find_by_name("administrator") ? "administrator" : "admin" if !cc.keys.include?(cont) # it's not in the db new_controller = new(:controller_name=>f.underscore.gsub!("_controller", ""), :last_modified=>Date.today) # add controller to controllers table as there's not a record corresponding with the file new_controller.actions << new_controller.action_list.map { |a| Action.new(:action_name=>a[1]) }# when a new controller is added, its actions must be added to the actions.file new_controller.save elsif cc[cont].modified? # file was modified since db was updated, so read the actions from the file, and add/delete as necessary action_names = cc[cont].actions_from_file # action_names is of the form ["index", "new", "edit", "create", "update"] Action.update_table_for(cc[cont],action_names) # finally modify the last_modified date of the controller record to match the actual file cc[cont].update_attribute(:last_modified,cc[cont].file_modification_time) end end ActionRole.assign_developer_access # delete any records in the controllers table for which there's no xx_controller.rb file... it must've been deleted cc.each { |name,controller| controller.destroy if !all_controller_names.map{|cn| cn.tableize.gsub!("_controllers","")}.include?(name) } end |
Instance Method Details
#action_list ⇒ Object
returns an array of arrays, each contains the controller controller_name and action name
120 121 122 |
# File 'app/models/controller.rb', line 120 def action_list actions_from_file.collect { |m| [model_name,m] } end |
#actions_from_file ⇒ Object
the actions returned are those that were in the file when it was loaded this is reasonable only because the actions are changed by the developer and never get changed “on the fly”. However this fact should be considered when testing!
108 109 110 111 112 113 |
# File 'app/models/controller.rb', line 108 def actions_from_file # there's a workaround here for some strangeness that appeared in Rails 3 # where public_instance_methods returns some spurious methods with the format # _one_time_conditions_valid_nnn? controller.public_instance_methods(false).reject{|m| m.match(/one_time_conditions_valid/)}.map(&:to_s) end |
#controller ⇒ Object
115 116 117 |
# File 'app/models/controller.rb', line 115 def controller (controller_name+"_controller").classify.constantize end |
#file ⇒ Object
64 65 66 67 68 69 70 71 |
# File 'app/models/controller.rb', line 64 def file all_paths = Controller.engine_controller_paths << CONTROLLERS_DIR controller_path = all_paths.detect do |path| full_path = File.join(path, "#{controller_name}_controller.rb") File.exists?(full_path) end File.new(File.join(controller_path, "#{controller_name}_controller.rb")) end |
#file_modification_time ⇒ Object
60 61 62 |
# File 'app/models/controller.rb', line 60 def file_modification_time file.mtime.getutc.to_datetime end |
#model_name ⇒ Object
101 102 103 |
# File 'app/models/controller.rb', line 101 def model_name controller_name.gsub("Controller","").underscore end |
#modified? ⇒ Boolean
a file is declared to be modified if it’s either older or newer than the last_modified date this triggers re-parsing the actions in the file whether it’s older or newer and so responds both to the file being edited and also the database being restored from an older version. Only by converting to string could I persuade two apparently equal DateTime objects to match!
56 57 58 |
# File 'app/models/controller.rb', line 56 def modified? file_modification_time.to_s != last_modified.getutc.to_datetime.to_s end |