Как получить доступ ко всем маршрутам, когда приложение и включенный в него гем AppEngine определяют контроллеры с одинаковыми именами? - PullRequest
2 голосов
/ 03 ноября 2011

У меня есть движок (разработанный мной / компанией, в которой я работаю), который мы используем в нескольких разных проектах.Я только что преобразовал его для работы с rails 3.1 с конвейером ресурсов, и все, кажется, работает ... по большей части.

Моя проблема в том, что мне нужно расширить функциональность UsersController с помощьюнемного специй для конкретного приложения, но я не уверен, как лучше это сделать.Движок не определяет действие Users#show, но это приложение нуждается в нем, поэтому я добавил в файл маршрутов:

JobEngine::Application.routes.draw do
  root :to => 'home#index'

  resource :users, :only => [:show]
  resources :jobs, :only => [:show]
end

Затем в своем приложении я создал UsersController:

class UsersController < MyEngine::UsersController
  def show
  end
end

Затем я сделал 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 < ApplicationController

, и тогда ссылка будет работать нормально.Однако контроллер двигателя MyEngine::UsersController уже наследуется от ApplicationController.Я могу поместить код в ApplicationController моего приложения (например, before_filter), и он будет работать, как и ожидалось, поэтому я знаю, что мое определение класса в конечном итоге попадает в ApplicationController моего приложения, почему помощник job_path не работает?

Когда я изменяю действие show на следующее:

def show
  job_path(3)
end

Я получаю ошибку:

ActionController::RoutingError (No route matches {:action=>"show", :controller=>"jobs", :id=>3}):
app/controllers/users_controller.rb:9:in `show'

Что еще больше смущает меня, потому что теперь он действительно распознает job_path как метод,но почему-то маршрутизатор не определяет, куда идти со всеми правильными параметрами.

Что я делаю не так?Как правильно расширить функциональность контроллера двигателя?Я видел вопрос о функциональности расширяющего движка здесь.

И последовал этому примеру кода, изменив определение моего класса, вместо этого заново открыв MyEngine::UsersController, но я все еще получаю те же самые результаты, касающиеся job_path(NUMBER)

ОБНОВЛЕНИЕ:

Хорошо, я вроде понял, что происходит.Допустим, у вашего движка есть маршрут 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), и она работает.

Я не полностью удовлетворен этим решением, потому что оно кажется немного ... странным.Возможно, у меня есть часть на этой странице, которая будет использоваться на отдельной не наследуемой странице.Теперь помощник по ссылкам будет работать только для одной из двух страниц, но никогда не для обеих = \ Я что-то здесь упустил ...?

Ответы [ 2 ]

1 голос
/ 27 декабря 2011

Попробуйте изменить путь монтирования в маршрутах основного приложения, указав ниже:

mount MyEngine::Engine => "/"

Это решит вашу проблему.

0 голосов
/ 27 декабря 2011

Хотя вы можете заставить этот подход работать, семантика не создает чистую архитектуру.Вы можете догадаться об этом из дублирования контроллера Users - это означает, что некоторые функции User обрабатываются в AppEngine, а некоторые - в самом родительском приложении.

Вместо этого подумайте о том, какие функциисуществует уникально в приложении и упакован в гем AppEngine.Возможно, с JobEngine , как вы его называете, ваш Users контроллер на самом деле представляет собой UsersStatisticsController, а в приложении контроллер представляет собой «настоящий универсальный» UsersController, который обрабатывает CRUD-профили, очередь сообщений и т. д.

Если вы чувствуете, что должны объединить их в единый контроллер (вместо того, чтобы давать им четкую номенклатуру), то лучше всего создать контроллер Namespaced , гдетем самым можно соединить различные функции.

Несмотря на то, что это добавляет сложности, обычно можно утверждать, что это наиболее надежное решение. Вот еще один пост на SO об этом

...