I have an engine (developed by me / the company I work for) that we use on several different projects. I just converted it to work with rails 3.1 w/ assets pipeline and everything seems to be working... for the most part.
My problem is that I need to extend the functionality of the UsersController
with a little bit of app-specific spice, but I'm not sure about the best way to do it. The engine doesn't define a Users#show
action, but this app does need it, so I added to the routes file:
JobEngine::Application.routes.draw do
root :to => 'home#index'
resource :users, :only => [:show]
resources :jobs, :only => [:show]
end
Then in my application I created the UsersController:
class UsersController < MyEngine::UsersController
def show
end
end
Then I made a users/show.html.haml
view, I've stripped it down to only show one of the problem lines:
= link_to "Somewhere", job_path(3)
This gives me an error that reads undefined method 'job_path' for #<#<Class:0x00000102d69900>:0x00000102d4ed30>
Which is bizarre because before I made my app's UsersController
inherit from MyEngine::UsersController
it worked just fine.
When I do rake routes
in the console, there are these lines:
users GET /users(.:format) {:action=>"show", :controller=>"users"}
job GET /jobs/:id(.:format) {:action=>"show", :controller=>"jobs"}
I can alter the class definition to be:
class UsersController < ApplicationController
and then the link works just fine. However, the engine's controller MyEngine::UsersController
already inherits from ApplicationController
. I can put code into my app's ApplicationController
(like a before_filter
) and it will run as expected, so I know my class definition does ultimately hit my app's ApplicationController
, why is the job_path helper not working?
When I change the show action to read:
def show
job_path(3)
end
I get the error:
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"jobs", :id=>3}):
app/controllers/users_controller.rb:9:in `show'
Which further confuses me because now it actually does recognize job_path as a method, but somehow the router isn't picking up where to go with all the correct parameters.
What am I doing wrong? What is the correct way to extend engine controller functionality? I saw the extending engine functionality question here.
And followed that code example, changing my class definition to instead re-open MyEngine::UsersController
but I still get the exact same results concerning job_path(NUMBER)
UPDATE:
Ok I sort of figured out what's going on. Let's say your engine has a job_path route, and your application has a job_path route. If you're on a page that was accessed via an engine's controller, you can call the engine's helper with just job_path
, but you can also call the main application's helper with main_app.job_path
.
Likewise, if you're on a page accessed via one of your application's controllers, you access the engine's helper with my_engine.job_path
and your own application's helper with job_path
. This is assuming that you have something like mount MyEngine::Engine => "/my_engine", :as => 'my_engine'
.
When you inherit an engine controller from your application, it then completely changes your route helpers to think you're in the context of the engine through the controller/view lifecycle. So to fix my problem all I really have to do is change it to be main_app.job_path(3)
and it works.
I'm not completely satisfied with this solution because it feels a little...weird. Maybe I have a partial on this page that will be used on a separate non-inheriting page. Now the link helper will only work for one of the two pages, but never both =\ Am I missing something here...?