2012-04-20 31 views
3

私はコントローラーの操作で参照できる汎用ルートを作成しようとしています。Rails 3に動的ルートを書き込む方法は?

私は、次の行を使用しています:

match ':action' => 'pages#:action', :as => 'action' 

はのは、ページコントローラで `foobarに」という名前のアクションをしましょう。私は

link_to 'Click Me', pages_foobar_path 

を見ることができます。問題は、そのルートを書き込もうとするとエラーInvalid route name: ':action'が発生することです。

マインドあなた、:asパラメータなしのライン

match ':action' => 'pages#:action' 

は完璧に動作しますが、その後、私のような、手動でパスを記述する必要があります。

link_to 'Click Me', '/pages/foobar' 

その周りにどのような方法を?

答えて

0

あなたがそのようなあなたのルートを記述する場合、それにアクセスするための正しい方法は次のとおりです。

link_to 'Click me', action_path(:action => 'foobar') 
+0

まず、お返事ありがとうございます。私は動的に名前を付けたパスを探していますので、明示的にアクションを指定するのではなく、 'foobar_path'を使ってアクセスできます。私は個々のパスのための ':as'オプションでそれを行うことができることを知っています。それを動的に行う方法はありますか?ありがとう! –

+0

なぜパスを動的にロードしたいのですか?ルータの設定に基づいたヘルパーであることはご存知ですか?私はレールのルータは動的だとは思わない... – thiagofm

2

私はあなたが限り取得することができると思います。

match ':action' => 'pages#:action' 
match '/pages/:action' => redirect(":action") # pages_path(:action) will match 
をリダイレクトすることによって

link_to 'Click me', pages_path(:action) 

これは最初の答えで示唆されたアプローチよりもタイピングが少ないですが、何か表現力がないようです。

あなたのビュークラスでmethod_missingをオーバーライドしてpages_ [stuff] _pathをキャッチし、適切な文字列を生成できるとします。

def method_missing(name, *args, &block) 
    if name =~ /^pages_[a-z]*_path$/ 
    "/#{name.to_s.gsub!(/^pages_/,'').gsub!(/_path$/,'')}" 
    else 
    super 
    end 
end 

私のmethod_missingの知識や正規表現の能力が不足している場合は、私を許して - うまくいけば、これは、少なくとも役に立つ方向性です。 はダイナミックは「Railsの起動時に自分の行動を認識し、経路を動的に生成する」という意味

+0

これは間違いなくトラックです。だから誰かがこれを行うためのより良い方法を提案しない限り、私は数日でこれを正しい答えとして選択します。 –

+0

フィードバックいただきありがとうございます。それは今朝テストしたところ、 'name'を文字列にキャストして、あなたのアクションにアルファベット以外の文字(「_」など)がないと仮定しても、後者はちょうど正規表現の微調整)。私に残されている唯一の質問はどこに置くのかです。テスト目的のために、私はそれをビューの一番上に置いていますが、それはぎこちないものです。あなたがこれを行い、良い点を見つけ出そうと決めたら、それについて聞いてみたいと思うだろう。 –

5

場合:

それは私がどうなるものではないのですが、それはありませんあなたはそれがどのなしでやってたいかリダイレクションもmethod_missingランタイムオーバーヘッドもありません。

あなただけにして、あなたのpages_controller.rbファイルのためにこれを行うにしたい場合はconfig/routes.rb

controller_filenames = Dir.new("#{Rails.root}/app/controllers").entries 
controller_filenames.each do |filename| 
    # you could restrict to only the pages_controller.rb on the next line, 
    # and in that case, you could simplify even more (see next example)... 
    if filename =~ /_controller\.rb$/ 
    controller_name = filename.sub(/.rb$/, "") 
    controller_route_name = controller_name.sub(/_controller$/, "") 
    controller = controller_name.camelize.constantize.new 
    controller.action_methods.each do |action| 
     # if you don't want the controller name in your path match, just omit it... 
     match "#{controller_route_name}/#{action}" => "#{controller_route_name}##{action}", :as => "#{controller_route_name}_#{action}" 
    end 
    end 
end 

で:ダイナミックは意味場合

controller_name = "pages_controller" 
controller_route_name = "pages" 
controller = controller_name.camelize.constantize.new 
controller.action_methods.each do |action| 
    # I've removed the controller_route_name from the match here... 
    match "#{action}" => "#{controller_route_name}##{action}", :as => "#{controller_route_name}_#{action}" 
end 

さて、「ルートを生成するたびにI新しいアクションを動的に生成する "

仲間は火で遊ぶ。既存のアクションのどれでも新しいアクションとルートを定義できます。例えば、Iはconfig/routes.rbでルートを定義することができる(これは任意既存のルートであってもよい):ApplicationControllerにおける方法で(再び、これは既存のアクションとすることができる)こと

match '/dynamic_define' => 'application#dynamic_define' 

カップル:

お使いのブラウザで
def dynamic_define 
    method_name = params[:mname] 
    self.class.send(:define_method, method_name) { 
    render :text => "output from #{method_name}" 
    } 
    Rails.application.routes.disable_clear_and_finalize = true 
    Rails.application.routes.draw do 
    match "/#{method_name}" => "application##{method_name}", :as => "application_#{method_name}" 
    end 
    render :text => "dynamic_define just created a new action named #{method_name}" 
end 

、あなたが訪問することができます:

/dynamic_define?mname=my_new_dynamic_action 
# browser renders "dynamic_define just created a new action named my_new_dynamic_action" 

そして訪問を:

/my_new_dynamic_action 
# browser renders "output from my_new_dynamic_action" 
関連する問題