嵌套资源 - 如何避免冗余路由?

时间:2011-01-29 01:13:42

标签: ruby-on-rails resources routing nested

我有这个资源树:

  • 论坛
    • 主题

我希望能够尽可能独立地访问它们。我想避免像/forum/:forum_id/topic/:topic_id/post/:id这样的冗余路由,因为我可以/post/:id

理想的路线如下:

/forums => Forums#index              # Lists every forum
/forum/new => Forums#new             # New forum
/forum/edit => Forums#edit           # Edit forum
/forum/:id  => Forums#show           # Shows forum
/forum/:id/forums Forums#index       # Lists nested forums
/forum/:id/topics => Topics#index    # Lists topics inside forum
/forum/:id/topic/new => Topics#new   # New topic
/topics => Topics#index              # Lists every topic
/topic/:id => Topics#show            # Shows topic
/topic/:id/posts => Posts#index      # Lists posts inside topic
/topic/:id/post/new => Posts#new     # New post
/posts => Posts#index                # Lists every post
/post/:id => Posts#show              # Shows post

模拟这种情况的最佳方法是什么?

这是我试过的:

resources :forums
resources :topics
resources :posts

resources :forums do
  resources :topics
end

resources :topics do
  resources :posts
end

问题是这些设置会产生许多无用的路线,例如:

/forums/:forum_id/topic/:id # Redundant - /topic/:id
/topics/:topic_id/post/:id  # Redundant - /post/:id
/topics/new                 # No current forum
/posts/new                  # No current topic

有没有办法指定要创建的路线?

在控制器中,如何处理映射到同一操作的多个路由?例如,在Topics#index内,我如何知道我应该处理GET /forum/:id/topics还是GET /topics

2 个答案:

答案 0 :(得分:2)

仅在index次操作中需要嵌套路由,其中​​父对象找到资源集合。否则它是关于SEO。大多数用户不会注意到他们的网址是如何生成的,也不关心所有关于搜索引擎的信息。我看到你要去哪里但是生成路由会更多的工作,因为这个例子中的约定是列出一行代码的资源。当然,你已经知道这一点,但这只是我对事物的看法。

a) forms_path #if you want to find all forms
b) topics_path #if you want to find all topics #possible use, maybe in a tag listing.
c) posts_path #if you want to find all posts #probably never use

您可能永远不会想要找到所有主题,特别是帖子,但这些将是要使用的路线。

d) form_topics_path(form) #find all topics of a given form 
e) form_topic_path(form, topic)  #only find one topic on a give form
f) topic_path #find a given topic

在最后两个e和f中,由于您知道自己想要哪个主题,因此不需要表单。如果你担心搜索引擎优化并让你的网址对搜索引擎很好,那么可能想要使用e。

g) form_topic_posts_path(form, topic) #I'm already confused 
h) form_topic_post_path(form, topic, post) #still to deep
i) topic_posts_path(topic) #most rails people think two levels is deep enough
j) topic_post_path(topic, post) #might be good for seo

这真的是SEO的问题,除了嵌套资源需要他们的父ID才能找到关联的帖子,例如传递form以查找相关主题,并传递{{1}找到相关的帖子。

如果您使用topictopic_path topics_pathpost_path,您可能会错过更好的网址,但是为了更好的网址可以阅读,但他们确实是不必要的。

在没有生成路线的情况下,确实没有对此的需求,因为这会使得这比仅仅在最终目标只是内务管理的一行中声明资源更复杂。

答案 1 :(得分:1)

我通过限制每个资源声明生成的路由来解决我的问题:

resources :forums do
  resources :topics, only: [ :index, :new, :create ]
end

scope except: [ :new, :create ] do
  resources :posts
  resources :topics do
    resources :posts, only: [ :index, :new, :create ]
  end  
end

至于控制器问题,我只是检查是否传递了id

# Topics#index
if forum_id = params[:forum_id]
  @topics = Forum.find(forum_id).topics.paginate page: params[:page]
else
  @topics = Topic.paginate page: params[:page]
end