rails 3.1 dynamic controller instantiation
I have a Rails Engine gem in which I want to load a HomeController class definition dynamically from an initializer. I can instantiate the class correctly, but when I go to call the index action, I get this error :
TypeError in HomeController#index
can't convert nil into String
Rails.root: /home/chris/test_app
Full Trace:
actionpack (3.1.0) lib/action_view/template/resolver.rb:16:in `<<'
actionpack (3.1.0) lib/action_view/template/resolver.rb:16:in `build'
actionpack (3.1.0) lib/action_view/template/resolver.rb:127:in `find_templates'
actionpack (3.1.0) lib/action_view/template/resolver.rb:45:in `find_all'
actionpack (3.1.0) lib/action_view/template/resolver.rb:76:in `cached'
actionpack (3.1.0) lib/action_view/template/resolver.rb:44:in `find_all'
actionpack (3.1.0) lib/action_view/path_set.rb:21:in `find_all'
actionpack (3.1.0) lib/action_view/path_set.rb:20:in `each'
actionpack (3.1.0) lib/action_view/path_set.rb:20:in `find_all'
actionpack (3.1.0) lib/action_view/path_set.rb:19:in `each'
actionpack (3.1.0) lib/action_view/path_set.rb:19:in `find_all'
actionpack (3.1.0) lib/action_view/path_set.rb:29:in `exists?'
actionpack (3.1.0) lib/action_view/lookup_context.rb:94:in `template_exists?'
I cut the trace off after the actionpack part because it was really long, but I think this is all the relevant information.
Here is my Engine class definition:
module MyGem
class Engine < Rails::Engine
initializer 'my_gem.load_middleware' do |app|
home_controller = create_controller 'HomeController'
end
def create_controller(class_name, &block)
klass = Class.new ApplicationController, &block
Object.const_set class_name, klass
return klass
end
end
end
this is when i have the root path set to home#index . if I create a home_controller.rb in app/controllers in either the application or the gem like so:
class HomeController < Applicati开发者_JS百科onController
end
then everything works fine and the index action is rendered appropriately, so I'm sure there is no problem with my routes, views, or application controller.
Any light shed on this issue would be much appreciated. edit the output of
HomeController.view_paths.join " : "
is
/home/chris/gems/my_gem/app/views : /home/chris/test_app/app/views
I'm not sure where you get the DSL "initializer" from... but that seems to cause a problem. It doesn't get executed on new()
This seems to work for me in Rails 3.0.7:
module MyGem
class Engine < Rails::Engine
def initialize
home_controller = create_controller 'HomeController'
end
# this doesn't seem to do anything...
#
# initializer 'my_gem.load_middleware' do |app|
# home_controller = create_controller 'HomeController'
# end
def create_controller(class_name, &block)
klass = Class.new ApplicationController::Base , &block # shouldn't this be ApplicationController::Base ?
# Object.const_set class_name, klass # module of superclass is ApplicationController, not Object
ApplicationController.const_set(class_name, klass) # name of the module containing superclass
puts "Klass created! : #{Object.constants}"
return klass
end
end
end
and running the code:
h = MyGem::Engine.new
Klass created! : [:Object, :Module, :Class, :Kernel, :NilClass, :NIL, :Data, :TrueClass, :TRUE, :FalseClass, :FALSE, :Encoding ... :BasicObject]
=> #<MyGem::Engine:0x00000006de9878>
> ApplicationController.const_get("HomeController")
=> ApplicationController::HomeController
精彩评论