当应用程序和包含的 AppEngine gem 定义具有相同名称的控制器时,如何访问所有路由? [英] How do I access all routes, when an App and an included AppEngine gem define controllers with the same name?

查看:44
本文介绍了当应用程序和包含的 AppEngine gem 定义具有相同名称的控制器时,如何访问所有路由?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个引擎(由我/我工作的公司开发),我们在几个不同的项目中使用它.我刚刚将它转换为与带有资产管道的 rails 3.1 一起使用,并且一切似乎都在工作......在大多数情况下.

我的问题是我需要使用一些特定于应用程序的香料来扩展 UsersController 的功能,但我不确定最好的方法.引擎没有定义 Users#show 动作,但这个应用确实需要它,所以我添加到路由文件中:

JobEngine::Application.routes.draw 做根:到 =>'家#索引'资源 :users, :only =>[:表演]资源 :jobs, :only =>[:表演]结尾

然后在我的应用程序中我创建了 UsersController:

class UsersController <我的引擎::用户控制器高清秀结尾结尾

然后我制作了一个 users/show.html.haml 视图,我已经将其剥离以仅显示问题行之一:

= link_to "Somewhere", job_path(3)

这给了我一个错误,读取 undefined method 'job_path' for #<#<Class:0x00000102d69900>:0x00000102d4ed30>

这很奇怪,因为之前我让我的应用程序的 UsersController 继承自 MyEngine::UsersController 它工作得很好.

当我在控制台中执行 rake routes 时,有以下几行:

users GET/users(.:format) {:action=>"show", :controller=>"users"}job GET/jobs/:id(.:format) {:action=>"show", :controller=>"jobs"}

我可以将类定义更改为:

class UsersController <应用控制器

然后链接工作得很好.然而,引擎的控制器MyEngine::UsersController 已经继承自ApplicationController.我可以将代码放入我的应用程序的 ApplicationController(就像一个 before_filter),它会按预期运行,所以我知道我的类定义最终会命中我的应用程序的 ApplicationController,为什么 job_path 助手不起作用?

当我将显示操作更改为阅读时:

def 显示作业路径(3)结尾

我收到错误:

ActionController::RoutingError(没有路由匹配 {:action=>"show", :controller=>"jobs", :id=>3}):app/controllers/users_controller.rb:9:in`show'

这让我更加困惑,因为现在它实际上确实将 job_path 识别为一种方法,但不知何故路由器没有选择所有正确参数的去向.

我做错了什么?扩展引擎控制器功能的正确方法是什么?我在这里看到了扩展引擎功能问题.

并遵循该代码示例,将我的类定义更改为重新打开 MyEngine::UsersController 但我仍然得到与 job_path(NUMBER) 完全相同的结果/p>

更新:

好的,我大概知道是怎么回事了.假设您的引擎有一个 job_path 路由,而您的应用程序有一个 job_path 路由.如果您在通过引擎控制器访问的页面上,您可以仅使用 job_path 调用引擎的帮助程序,但您也可以使用 main_app.job_path 调用主应用程序的帮助程序代码>.

同样,如果您在通过应用程序的控制器之一访问的页面上,您可以使用 my_engine.job_path 访问引擎的帮助程序,并使用 job_path 访问您自己的应用程序的帮助程序.这是假设你有类似 mount MyEngine::Engine => 的东西."/my_engine", :as =>'my_engine'.

当您从应用程序继承引擎控制器时,它会彻底改变您的路由助手,让您认为您在控制器/视图生命周期中处于引擎的上下文中.所以要解决我的问题,我真正需要做的就是将其更改为 main_app.job_path(3) 并且它可以工作.

我对这个解决方案并不完全满意,因为感觉有点……奇怪.也许我在此页面上有一部分将用于单独的非继承页面.现在链接助手只适用于两个页面之一,但永远不会同时使用 =\ 我在这里遗漏了什么......?

解决方案

尽管您可以使这种方法起作用,但语义并不能创建干净的架构.您可以从 Users 控制器的重复中推测出这一点 - 这意味着某些 User 功能在 AppEngine 中处理,而另一些在父应用程序中处理.>

相反,请考虑应用程序中唯一存在的功能,以及打包到 AppEngine gem 中的功能.也许对于 JobEngine,正如您所说的那样,您的 Users 控制器实际上有一个 UsersStatisticsController,并且在应用程序中,控制器有 '真正的通用'UsersController 处理 CRUD、配置文件、消息队列等

如果您觉得必须将它们统一到一个控制器中(而不是给它们不同的命名法),那么您最好创建一个命名空间控制器,从而可以将各种功能结合起来.

尽管这增加了复杂性,但通常可以说这是最合理的解决方案.这是另一篇关于 SO 的帖子

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...?

解决方案

Though you can make this approach work, the semantics do not create a clean architecture. You can surmise this from the duplication of the Users controller - which implies that some User functionality is handled in the AppEngine, and some is handled in the parent app itself.

Instead, think about what functionality exists uniquely within the app, and which is packaged into the AppEngine gem. Perhaps with JobEngine, as you call it, your Users controller there is actually a UsersStatisticsController and, in the app, the controller there is the 'true generic' UsersController that handles CRUD, profiles, message queue, etc.

If you feel you must unify them into a single controller (rather than giving them distinct nomenclature), then you are best to create a Namespaced controller, where the various functionality can be conjoined thereby.

Even though this adds complexity, it's generally arguable that this is the most sound solution. Here's another post on SO about it

这篇关于当应用程序和包含的 AppEngine gem 定义具有相同名称的控制器时,如何访问所有路由?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆