2011-08-02 15 views
15

Rails3エンジンでは、独自のモデル/コントローラ/ビューとコースルートが付属しています。問題は次のとおりです。アプリケーションルートの前(または後)にエンジンルートがロードされていることと、存在する他のすべてのエンジンがどのように確実にロードされるのでしょうか?エンジンからのルートロードオーダーの制御

ここでは私のRailsアプリのルートの例です:

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

そして、私のエンジン:

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

ので、デフォルトのエンジンでルートがアプリケーションのものの後にロードされます。これは、私のアプリでそのキャッチオールルートのためにエンジンルートがアクセス不能であることを意味します。エンジンルートを最初に(または最後に)ロードするにはどうすればいいですか?

+0

http://edgeguides.rubyonrails.org/configuring.htmlを見てみましたか?私はあなたがフックとイニシャライザを使って何をしたいのかをかなり確信しています –

+0

それはhttp://stackoverflow.com/questions/6310832/how-to-override-rails-app-routes-from-an-の複製ではありませんか?エンジン? –

+0

ところで、私は、エンジンルートは常にアプリケーションルートの後に読み込まれると信じています。 –

答えて

28

あなたがしようとしていることは、ちょっと難しいことです。前述したように、エンジンのルートは、アプリのルートの後に読み込まれ、この動作をオーバーライドすると問題がある可能性があります。私はあなたが試すことができるいくつかのことを考えることができます。ルーティングパス初期化子後

使用アン初期化子

レールソース内部engine.rbにおける初期化子はあなたが後にしているものを達成する一つの方法は、それが扱っ機能をフックしようとすることです、があります。初期化子は、デフォルトでは次のようになります。

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 

基本的に、これはRailsが知っていることをファイルすべてのルートへのパスを取得し、試してみて、ルートのリロード機能にそれらを追加する必要があります(あなたのルートをreloades事がのために自動的にファイルあなたが変更された場合はあなたに)。この直後に別のイニシャライザを定義して、ルートリローダに格納されているパスを調べ、エンジンに属するパスを取り出し、パス配列から削除して最後に挿入しますパス配列のだから、あなたの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 

これは、または、私は実際にそれをお勧めしませんいずれかのように動作しない可能性があり、それは(レールの根性で遊んすなわち醜いハック)特にエレガントではありません。

利用のRails 3.1

これはオプションではないかもしれないが、それであれば、私はおそらく、この1で行くだろう。 Rails 3.1では、フルとマウント可能な2種類のエンジンを用意しています(ここではan SO question talking about some of the differencesです)。しかし、本質的にエンジンをマウント可能なエンジンに変更すると、マウント可能なエンジンのルートは名前空間になり、メインアプリケーションのルートファイルに明示的に含めることができます。:

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

あなたはまた、スコープは、あなたのエンジンのルートをマウントし、他の空想routyもの(詳細here)のすべてのソートを行うことができます。短いストーリー、あなたが3.1に行くことができるなら、これは使用するアプローチです。

動的た瞬間に周りの最もよく知られているRailsのエンジンのあなたの主なアプリケーション

一つにあなたのエンジンからのルートを挿入しますが考案です。今、deviseはあなたのアプリにかなりのルートを追加する可能性のあるエンジンですが、あなたがdeviseソースを見ると、実際にはconfig/routes.rbというファイルはまったくありません。これは、deviseがメインアプリのroutes.rbファイルにルーティングの良さを動的に追加するためです。

あなたは工夫が付属したモデルジェネレータを実行すると、発電機がどうなるものの一つは、右Rails.application.routes.draw do行の後、あなたのroutes.rbをファイルの先頭に、このようなdevise_for :modelなどの行を追加しています。

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

、devise_for(lib/devise/rails/routes.rb中)工夫の一環として、来る魔法の方法であるが、本質的にそれは以下となります。だからあなたのroute.rbを使用すると、Userモデルを作成するための発電機を実行した後、このようになります私たちが皆さんが生成したモデルに基づいて知っている一連の定期的なルートを作成してください。

私たちが知る必要があることは、アプリケーションroutes.rbファイルにこの行を挿入する方法です。その後、メインアプリケーションroutes.rbファイルの先頭にルートを挿入するジェネレータをエンジンに書き込むことができます。これについてはlib/generators/devise/devise_generator.rbをご覧ください。 add_devise_routesメソッドでは、最後の行はroute devise_routeです。 Routeは、渡された文字列をメインアプリのroutes.rbファイルに挿入するThorアクションです。だから我々は我々自身の発電機を書き込み、例えば似た何かを行うことができます。:

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

あなたは必ずすべての発電インフラが整備されているが、それはそれの本質だようにする必要があります。 Deviseはいくつかの非常にスマートなレールで書かれており、かなり多くの人が使用しています。私がこれを提案した3つのことのうち、私はあなたの問題を扱う方法です(レール3.1への移行はおそらくオプションではないと考えられるので)。

+0

これは素晴らしいことです。これに答える努力をいただきありがとうございます。 – Grocery

+0

私は自分の夢をあきらめて、実際のルーティングコードにパッチを当てるよりもむしろ開発者のアプローチを使用しました。結局、カスタムスコープで物をラップすると、はるかに柔軟になりました。 –

0

私は専門家ではありませんが、私は昨日sferik/rails_adminと一緒にルーティングソリューションを見つけました。 rails_admin:installレーキタスクでは、ファイルの先頭にmount RailsAdmin::Engine => '/admin', :as => 'rails_admin'を追加してファイルを直接変更するので、ルートの優先順位が常に最高になるようにします。それmount方法は、自分の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 

これはあなたの解決策になるだろうか?

2

今は同じ問題があります。私が思いついた、特にエレガントで安全な解決策の1つは、あなたの宝石ファイルの最後に別のエンジンの宝石を追加することです。

編集:実は、反し、ルーティング宝石は、そのルートの前にすべての他のエンジン宝石が最後にロードされるようにリストされる必要があります。

+1

うん。基本的にシャッフルの宝石で、戦略を立てるまで続きます。宝石がroute.rb内で明示的に呼び出すメソッドを提供することは、無限に優れています。そうすれば、それらのルートが必要な場所を制御することができます。 – Grocery

関連する問題