Reputation: 533
I'd like to set my application's root to an action of an engine's controller. I thought this in my config/routes.rb
would get it done:
root action: :show, controller: :pages, module: :MyEngine
But I'm getting a uninitialized constant PagesController
error. Are the routes being set before the engine's controllers are being auto loaded?
Upvotes: 2
Views: 1093
Reputation: 533
I explicitly declared the controller I was using without the name spacing in config/routes.rb
.
PagesController = MyEngine::PagesController
root action: :show, controller: :pages
That did it. I'm wondering if I found a bug with the module
option?
Upvotes: 0
Reputation: 905
The engine's controllers won't be loaded until after it's mounted, I believe. I couldn't find a way to route to an engine the way you want, but I did find these ways:
1) Mount the engine at root (probably not strictly what you wanted)
mount MyEngine => '/', as: :myengine
2) Redirect root to the engine
# For redirecting to the engine's mount
root to: redirect { Rails.application.routes.url_helpers.myengine_path }
# For a specific engine path
root to: redirect { MyEngine.routes.url_helpers.some_path }
If you don't mind hard-coding your engine path, you can just:
root to: '/myengine/url'
There probably exists a better way of handling these helpers in the routes, but this was the most direct way I could find. I did stumble across this answer on a slightly related question that mentions creating a helper specifically for this kind of thing. Adapting it for use with an engine might give something like:
class UrlRedirectHelper
# This makes the case where you just want to use the main app's routes less verbose
def self.method_missing(method, *args, **kwargs)
new.public_send(method, *args, **kwargs)
end
# This is some entirely unnecessary sugar, I just like the way it reads
def self.for(engine)
new(engine)
end
def initialize(engine = Rails.application)
@engine = engine
end
# This is called by `redirect` when it's preparing to redirect the user
def call(_params, _request)
url_helpers.public_send(@method, *@args, **@kwargs)
end
def method_missing(method, *args, **kwargs)
super unless url_helpers.respond_to? method
@method = method
@args = args
@kwargs = kwargs
self
end
private
# you could also `delegate` this, but it keeps the API cleaner to make it private
def url_helpers
@engine.routes.url_helpers
end
end
Which is then used like so:
get :somepath, to: redirect(UrlRedirectHelper.some_other_path)
# or, for an engine
get :somepath, to: redirect(UrlRedirectHelper.for(MyEngine).some_other_path)
Upvotes: 4