开发者

Routing more than one action to the same controller and action

I am trying to get something like this working on my Rails app:

match '/:language', :to => 'posts#search_result'
match '/:tag', :to => 'posts#search_result'
match '/:language/:tag', :to =>开发者_JAVA百科; 'posts#search_result'

I am using this search_result action to filter some posts depending of the language and the tag.

The problem is that sometimes :tag will be nil or :language will be nil; so i have these 3 possibilities when calling the action:

<%=link_to "Spanish", {:controller => 'posts', :action => 'search_result', :language => "spanish"} %>

<%= link_to "Spanish", {:controller => 'posts', :action => 'search_result', :language => "spanish", :tag => @tag} %>

<%=link_to "#{tag.name}", {:controller => 'posts', :action => 'search_result', :tag => @tag} %>

And I am expection to have URLs like:

/spanish          (for the first case)
/spanish/rails    (where rails is a tag, for the second case)
/rails            (for the third case)

But right now i am getting the rigth thing for the first and third case, but for the second case i am getting: /spanish?tag=rails or again /spanish (depending on if i had selected a tag first or a language first).

I hope i explained myself right. Any idea??. thanks!.


The router cannot tell the difference between a :language and a :tag.

Just because your routes say "language" and "tag" when you are constructing your code in the view.. remember that in the html this has been translated into just plain ole URLs eg /spanish or /rails

the route then has to be figured out from this URL.

Now as I said, the router can't tell that a particular word is a language or a tag... and the plain-ole-URL doesn't have the word "tag" or "language" in it anymore... so your two routes here:

match '/:language', :to => 'posts#search_result'
match '/:tag', :to => 'posts#search_result'

are both the same kind of URL

Just a single token after the slash. Here are some examples that will match that route:

/greek
/spanish
/rails
/urdu
/whatever

They will all match the first route that matches on "a single token after a slash"... which means your router will match all of them to the "language" route and will never ever match the "/:tag" route, because it's already matched on the route above.

he he: it's all greek to the router ;)

Edit:

Hi, this is helping me a lot to understand how routing works.. but still i can't see it clear. I understand what you said, and so basically i understand i should do something like match '/tags/:tag to at least only route to posts#search_result the URLS starting by /tag .. what would be a solution??

yes, "/tags/:tag" would be clear and unambiguous, but if you want it to truly flexible in tag vs language you would be better served by the simple:

match '/posts/search', :to => 'posts#search_result'

which can use any of your link_to examples above to generate eg:

/posts/search?tag=rails
/posts/search?language=spanish
/posts/search?language=spanish&tag=rails

It's also far more clear what is being passed and why.

The description of the third URL is "I'm searching for a set of posts which have language = spanish and tag = rails"

Your URL should reflect the resource (which in this case is a set of posts) everything else is better done as query params.


Instead of defining /:language and /:language/:tag separately, define them together, with /:tag as an optional URI element.

match '/:language(/:tag)', :to => 'posts#search_result'

I believe routes are matched (and URIs generated from them) in the order that the routes are defined. You defined /:lang before you defined /:lang/:tag, so it matched /:lang and made :tag a GET parameter. I suppose you could optimize the ordering of your definitions, but I believe using the above syntax is the preferred method.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜