Nested resources. How to avoid redundant routes?

I have this resource tree:

  • Forum
    • Theme
      • Message

I want to have access to them wherever possible. I want to avoid redundant routes like /forum/:forum_id/topic/:topic_id/post/:id , because I can just do /post/:id .

Ideal routes are as follows:

 /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 

What is the best way to simulate this situation?

Here is what I tried:

 resources :forums resources :topics resources :posts resources :forums do resources :topics end resources :topics do resources :posts end 

The problem is that these settings create many useless routes, for example:

 /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 

Can I specify which routes to create?

In controllers, how do I handle multiple routes mapped to the same action? For example, inside the Topics#index , how can I find out if I should handle GET /forum/:id/topics or GET /topics ?

+4
source share
2 answers

Nested routes are needed only for index actions, where the resource set is found by the parent. Otherwise, it’s about SEO. Most users will not notice how their URLs are generated and do not care about all search engines. I see where you are going, but it will work more so as not to generate routes, since in this example the agreement contains a list of resources with one line of code. And, of course, you already know this, but this is just my business.

 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 

You probably will never want to find all the topics and especially the posts, but these will be the routes to 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 

In the last two, e and f, the form is not needed, since you know what topic you want. If you are worried about SEO and get good URLs for search engines, then you probably want to use 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 

It really is a SEO issue and keeping your URLs apart from the embedded resource, which needs their parent id to find related posts, such as passing a form to find related topics, and pass a topic to find.

If you use topic_path , topics_path post_path , post_path , you are inferior to better urls, but in terms of improving the urls to read, but they really aren't needed.

In terms of the lack of route generation, this is actually not a requirement for this, because it will make it more difficult than simply declaring the resource in one line, where the ultimate goal is just the household.

+2
source

I solved my problem by restricting the routes generated by each resource declaration:

 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 

Regarding the problem with the controller, I just check if id passed:

 # 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 
+1
source

Source: https://habr.com/ru/post/1337560/


All Articles