2011-08-02 36 views
15

Vì vậy, trong Rails3, Động cơ đi kèm với mô hình/bộ điều khiển/chế độ xem của riêng họ và tất nhiên là tuyến đường. Bây giờ câu hỏi đặt ra là: Làm thế nào để bạn đảm bảo rằng các tuyến đường Engine sẽ được tải trước (hoặc sau) các tuyến ứng dụng và tất cả các Công cụ khác hiện diện?Kiểm soát các thứ tự tải tuyến từ Engines

Dưới đây là một ví dụ về các tuyến ứng dụng Rails của tôi:

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

Và động cơ của tôi:

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

Vì vậy, bằng động cơ mặc định các tuyến đường sẽ được nạp sau khi những ứng dụng. Điều này có nghĩa là các tuyến Engine không thể truy cập được do tuyến đường bắt tất cả trong ứng dụng của tôi. Làm thế nào có thể buộc các tuyến đường của Engine được nạp đầu tiên (hoặc cuối cùng)?

+0

Bạn đã thử xem http://edgeguides.rubyonrails.org/configuring.html chưa? Tôi khá chắc chắn bạn có thể làm những gì bạn muốn bằng cách sử dụng móc & initializers –

+0

Đó không phải là một bản sao của http://stackoverflow.com/questions/6310832/how-to-override-rails-app-routes-from-an- động cơ ? –

+0

BTW, tôi tin rằng các tuyến động cơ luôn được tải sau các tuyến ứng dụng. –

Trả lời

28

Điều bạn đang cố gắng làm là khá khó khăn. Như đã được đề cập các tuyến đường công cụ được tải sau khi các tuyến ứng dụng và ghi đè hành vi này có thể có vấn đề. Tôi có thể nghĩ ra một vài điều mà bạn có thể thử.

Sử dụng Một Initializer Sau Routing Paths Initializer

Có một initializer trong engine.rb bên trong nguồn đường ray, một cách để thực hiện những gì bạn đang sau là cố gắng để móc vào các chức năng mà nó đối diện. Initializer trông như thế này theo mặc định:

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 

Về cơ bản, điều này sẽ mất các đường dẫn cho tất cả các tập tin tuyến đường Rails biết về và cố gắng và thêm chúng vào các tuyến đường reloader (điều mà reloades nộp tuyến đường của bạn automagically cho bạn nếu nó được thay đổi). Bạn có thể định nghĩa một initializer khác được thực hiện ngay sau cái này, sau đó bạn sẽ kiểm tra các đường dẫn được lưu trữ trong reloader routes, kéo ra đường dẫn thuộc về engine của bạn, loại bỏ nó khỏi mảng path và chèn nó trở lại, nhưng ở cuối của mảng đường dẫn. Vì vậy, trong config/application.rb của bạn:

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 

này có thể hoặc không thể làm việc, một trong hai cách tôi không thực sự khuyên bạn nên nó, nó không phải là đặc biệt thanh lịch (ví dụ: hack xấu xí chơi với ruột của đường ray).

Sử dụng Rails 3.1

này có thể không là một lựa chọn, nhưng nếu nó là, tôi có thể đi với một này. Trong Rails 3.1, bạn có thể có 2 loại Động cơ khác nhau, đầy đủ và có thể lắp (ở đây là an SO question talking about some of the differences). Nhưng về bản chất, bạn sẽ thay đổi Engine của mình thành công cụ có thể gắn kết, các tuyến đường trong công cụ có thể gắn kết được đặt tên và bạn có thể bao gồm chúng một cách rõ ràng trong tệp tuyến đường của ứng dụng chính của bạn, ví dụ::

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

Bạn cũng có thể điều chỉnh các tuyến động cơ được gắn và thực hiện tất cả các thứ khác lạ mắt (xem thêm thông tin here). Dài câu chuyện ngắn, nếu bạn có thể đi đến 3.1 thì đây là cách tiếp cận để sử dụng.

động Chèn các tuyến đường từ động cơ của bạn vào bạn chính App

Một trong những động cơ Rails nổi tiếng nhất xung quanh lúc này là lập mưu. Bây giờ, nghĩ ra là một công cụ có khả năng sẽ thêm khá nhiều tuyến đường vào ứng dụng của bạn, nhưng nếu bạn nhìn vào nguồn gốc, bạn sẽ thấy rằng nó không thực sự có một tệp config/routes.rb nào cả! Điều này là bởi vì tự động thêm tính năng định tuyến của nó vào tệp routes.rb của ứng dụng chính của bạn.

Khi bạn chạy trình tạo mô hình đi kèm với thiết lập, một trong những điều mà trình tạo sẽ làm là thêm một dòng như devise_for :model ở đầu tệp routes.rb của bạn, ngay sau dòng Rails.application.routes.draw do. Vì vậy, route.rb của bạn trông giống như này sau khi bạn thực hiện một máy phát điện để tạo ra một mô hình tài:

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

Bây giờ, devise_for là một phương pháp kỳ diệu mà đến như là một phần của devise (trong lib/devise/rails/routes.rb), nhưng trong bản chất nó sẽ tạo một loạt các tuyến đường thông thường mà tất cả chúng ta đều biết dựa trên mô hình mà bạn đã tạo. Điều chúng ta cần biết, là cách đưa ra dòng này trong tệp ứng dụng routes.rb, sau đó chúng ta có thể viết trình tạo trong công cụ của chúng tôi sẽ chèn bất kỳ tuyến đường nào của chúng tôi ở đầu các ứng dụng chính routes.rb tệp. Đối với điều này, chúng tôi xem xét lib/generators/devise/devise_generator.rb. Trong phương thức add_devise_routes dòng cuối cùng là route devise_route. Route là một hành động Thor chèn chuỗi được chuyển vào chuỗi đó vào tệp routes.rb của ứng dụng chính. Vì vậy, chúng ta có thể viết một máy phát điện của riêng của chúng tôi và làm điều gì đó tương tự như ví dụ .:

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

Tất nhiên bạn sẽ cần phải chắc chắn rằng tất cả các cơ sở hạ tầng phát được đặt ra nhưng đó là bản chất của nó. Devise được viết bởi một số dudes rails rất thông minh và được sử dụng bởi khá nhiều người, thi đua những gì họ làm có thể là một cách khá tốt để đi. Trong số 3 điều mà tôi đề nghị, đây là cách tôi sẽ xử lý vấn đề của bạn (cho rằng việc chuyển sang đường ray 3.1 có lẽ không phải là một lựa chọn).

+0

Điều này thật tuyệt. Cảm ơn bạn đã nỗ lực trả lời câu hỏi này. – Grocery

+0

Tôi đã từ bỏ ước mơ của mình và sử dụng cách tiếp cận sáng tạo thay vì khỉ vá mã định tuyến thực tế, cuối cùng nó linh hoạt hơn nhiều đặc biệt là khi bạn đang gói mọi thứ trong phạm vi tùy chỉnh. –

0

Tôi không phải là chuyên gia, nhưng tôi đã chơi với sferik/rails_admin hôm qua khi tôi đi qua giải pháp định tuyến của họ. Với nhiệm vụ rake rails_admin:install, họ trực tiếp sửa đổi tệp config/routes.rb của bạn bằng cách thêm mount RailsAdmin::Engine => '/admin', :as => 'rails_admin' vào đầu tệp để đảm bảo tuyến đường của họ luôn có mức độ ưu tiên cao nhất. Phương thức mount đề cập đến các tuyến đường riêng của chúng.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 

Đây có phải là giải pháp của bạn không?

2

Có cùng sự cố ngay bây giờ. Một giải pháp khác không phải đặc biệt thanh lịch nhưng an toàn mà tôi đưa ra là thêm một gem khác vào cuối tệp gem của bạn, chỉ chứa đựng tất cả các tuyến đường, không có gì khác.

Sửa: Thực ra, counterintuitively, viên ngọc định tuyến cần phải được liệt kê trước tất cả đá quý cơ khác cho các tuyến đường của nó được nạp trước.

+1

Vâng. Đó là cơ bản shuffle đá quý xung quanh cho đến khi nó hoạt động chiến lược.Đó là vô cùng tốt hơn cho đá quý để cung cấp một phương pháp mà bạn gọi một cách rõ ràng trong routes.rb của bạn. Bằng cách đó bạn có thể kiểm soát nơi bạn muốn các tuyến đường đó (nếu có). – Grocery

Các vấn đề liên quan