2011-08-02 13 views
15

Tak więc w Rails3 Silniki mają własne modele/kontrolery/widoki i oczywiście trasy. Teraz pytanie brzmi: w jaki sposób można upewnić się, że trasy silnika zostaną załadowane przed (lub po) trasami aplikacji i wszystkimi innymi silnikami, które są obecne?Sterowanie kolejnością ładowania tras z silników

Oto przykład z moich tras Rails aplikacji:

match '*(path)', :to => 'foo_controller#bar_action' 

A moja silnika:

match '/news', :to => 'bar_controller#foo_action' 

Więc przez domyślne Silniki tras zostanie załadowany po tych aplikacji. Oznacza to, że trasy z silnika są niedostępne ze względu na tę ścieżkę catch-all w mojej aplikacji. Jak zmusić trasy do załadowania najpierw (lub ostatnio)?

+0

Czy próbowałeś już spojrzeć na http://edgeguides.rubyonrails.org/configuring.html? Jestem prawie pewien, że możesz robić, co chcesz, używając haczyków i inicjalizatorów. –

+0

Czy to nie jest duplikat http://stackoverflow.com/questions/6310832/how-to-override-rails-app-routes-from-an- silnik ? –

+0

BTW, Wierzę, że trasy silników są zawsze ładowane po trasach aplikacji. –

Odpowiedz

28

To, co próbujesz zrobić, jest dość trudne. Jak już wspomniano, trasy silnika są ładowane po trasach aplikacji, a nadpisanie tego zachowania może być problematyczne. Mogę wymyślić kilka rzeczy, które możesz wypróbować.

użycie inicjator Po Routing Ścieżki Initializer

Jest initializer w engine.rb wewnątrz źródła szyny, jeden sposób, aby osiągnąć to, co jesteś po to, aby spróbować podpiąć do funkcjonalności, która ma do czynienia. Inicjatora wygląda to domyślnie:

initializer :add_routing_paths do |app| 
    paths.config.routes.to_a.each do |route| 
    app.routes_reloader.paths.unshift(route) if File.exists?(route) 
    end 
end 

Zasadniczo powinno to ścieżki do wszystkich plików trasach Szyny o nich wiedział i spróbować dodać je do Reloader trasy (rzeczy, które reloades Twoje trasy złożyć automagicznie dla ty, jeśli to się zmieni). Możesz zdefiniować inny inicjalizator, który zostanie wykonany zaraz po tym, następnie przejrzysz ścieżki przechowywane w reloaderze tras, wyciągniesz ścieżkę należącą do twojego silnika, usuniesz ją z tablicy ścieżek i wstawisz z powrotem, ale na końcu z tablicy ścieżek. Tak w config/application.rb:

class Application < Rails::Application 
    initializer :munge_routing_paths, :after => :add_routing_paths do |app| 
    engine_routes_path = app.routes_reloader.paths.select{|path| path =~ /<regex that matches path to my engine>/}.first 
    app.routes_reloader.paths.delete(engine_routes_path) 
    app.routes_reloader.paths << engine_routes_path 
    end 
end 

To może lub nie może pracować, albo sposób naprawdę nie polecam, to nie jest szczególnie elegancki (to znaczy brzydki hack, grając z wnętrzności szynach).

Stosować Rails 3.1

To nie może być opcja, ale jeśli tak, to pewnie bym go z tego. W Rails 3.1 możesz mieć 2 różne typy silników, pełne i montowalne (tutaj jest an SO question talking about some of the differences). Ale w istocie zmieniłbyś swój silnik tak, by był montowalnym silnikiem, trasy w montowalnym silniku są nazwane i możesz je jawnie zawrzeć w pliku tras swojej głównej aplikacji, np.:

Rails.application.routes.draw do 
    mount MyEngine::Engine => "/news" 
end 

Można również zakres twoi montowane trasy silnik i wszelkiego rodzaju inne rzeczy wyobraźnia routy (więcej here). Krótko mówiąc, jeśli możesz przejść do 3.1, to jest to podejście do użycia.

dynamicznie wstawić marszruty z silnika do swojego głównego App

Jeden z najbardziej znanych silników Rails wokół tej chwili jest Devise. Teraz devise to silnik, który potencjalnie doda całkiem sporo tras do twojej aplikacji, ale jeśli spojrzysz na źródło devise, zobaczysz, że w rzeczywistości nie ma pliku config/routes.rb! Dzieje się tak, ponieważ program dynamicznie dodaje swoją dobroć routingu do pliku głównej aplikacji o numerze routes.rb.

Po uruchomieniu generatora modelu dostarczanego wraz z urządzeniem, jedną z rzeczy, które zrobi generator, jest dodanie linii, na przykład devise_for :model, u góry pliku routes.rb, tuż za linią Rails.application.routes.draw do. Więc route.rb wygląda podobnie do tego po wykonaniu generator stworzenie modelu użytkownika:

Rails.application.routes.draw do 
    devise_for :users 
    ... 
end 

Teraz devise_for to magiczna metoda, która przychodzi jako część devise (w lib/devise/rails/routes.rb), ale w istocie to będzie stwórz garść zwykłych tras, które wszyscy znamy na podstawie wygenerowanego przez Ciebie modelu.

Rzeczą, którą musimy wiedzieć, jest to, jak zaprojektować wstawić tę linię w pliku aplikacji routes.rb, a następnie możemy napisać generator w naszym silniku, który wstawi dowolną z naszych tras na górze głównego pliku aplikacji routes.rb. W tym celu patrzymy na lib/generators/devise/devise_generator.rb. W metodzie add_devise_routes ostatnia linia to route devise_route. Route to akcja Thor, która wstawia ciąg przekazany do niego do pliku głównej aplikacji o numerze routes.rb. Tak więc możemy napisać generator nasz własny i zrobić coś podobnego np .:

class MyCrazyGenerator < Rails::Generators::NamedBase 
    ... 
    def add_my_crazy_routes 
    my_route = "match '/news', :to => 'bar_controller#foo_action'" 
    route my_route 
    end 
end 

Oczywiście trzeba by upewnić się, że cała infrastruktura generator jest na swoim miejscu, ale to esencja tego. Devise jest napisany przez niektórych bardzo sprytnych kolesi i wykorzystywany przez całkiem sporo ludzi, a naśladowanie tego, co robią, jest całkiem niezłą drogą. Spośród 3 rzeczy, które zasugerowałem, byłby to sposób, w jaki poradziłbym sobie z twoim problemem (biorąc pod uwagę, że przejście na tor 3.1 nie jest prawdopodobnie opcją).

+0

To jest świetne. Dziękuję za wysiłek w odpowiedzi na to. – Grocery

+0

Poddałem się moim marzeniom i wykorzystałem podejście opracowane raczej niż małpowanie łatające rzeczywisty kod trasy, w końcu jego znacznie bardziej elastyczne, zwłaszcza gdy owijasz rzeczy w niestandardowe zakresy. –

0

Nie jestem ekspertem, ale grałem z sferik/rails_admin wczoraj, kiedy natknąłem się na ich rozwiązanie routingu. Za pomocą zadania rake z rails_admin:install bezpośrednio modyfikują plik config/routes.rb, dodając na początku pliku mount RailsAdmin::Engine => '/admin', :as => 'rails_admin', aby upewnić się, że ich trasy mają zawsze najwyższy priorytet. Że mount metoda odnosi się do własnej routes.rb:

RailsAdmin::Engine.routes.draw do 
    # Prefix route urls with "admin" and route names with "rails_admin_" 
    scope "history", :as => "history" do 
    controller "history" do 
     [...] 
    end 
    end 
end 

Może to być rozwiązanie?

2

Masz ten sam problem właśnie teraz. Jeszcze jednym, niezbyt eleganckim, ale bezpiecznym rozwiązaniem, które wymyśliłem, jest dodanie kolejnego klejnotu silnika na końcu pliku gem, zawierającego tylko połowę całej trasy, nic więcej.

Edit: Właściwie counterintuitively, gem routingu musi być wymienione przed wszystkie inne kamienie silników do swoich tras być załadowany jako ostatni.

+1

Tak. Jest to zasadniczo tasowanie klejnotów, dopóki nie działa strategia.Dla gemów jest nieskończenie lepiej, jeśli chodzi o metodę, którą jawnie wywołujesz w twoich routes.rb. W ten sposób możesz kontrolować, gdzie chcesz te trasy (jeśli w ogóle). – Grocery

Powiązane problemy