0

Using Rails 3.1.1 and the gem acts_as_tree. I have googled the issue and checked similar questions here at SO (the answers are too old, or irrelevant).

I have a model called articles with a route that today looks like:

  resources :articles, :path => '', :only => :show 
  resources :articles, :path => 'articles', :except => :show

I have three articles: "book", "chapter1" and "chapter2". Where book is parent to chapter1 and chapter2.

Today, my path to each article is: host.com/book, host.com/chapter1 and host.com/chapter2. I want the url path to be host.com/book/chapter1 and host.com/book/chapter2 , i.e. nested routes.

How can I create this in a clean simple manner?

Basically, I want a path that will be host.com/:parent_id/:parent_id/:id with N numbers of :parent_id. Pretty much how Wordpress-articles are routed.

I don't believe route globbers is the solution, but I might be wrong. It seems to give the same result for host.com/:id and host.com/foo/bar/:id which will result in duplicate content.

Christoffer
  • 2,271
  • 3
  • 26
  • 57

4 Answers4

1

You have three "articles"... "book", "chapter1" and "chapter2" all represent same 'resources', named 'articles'. Same 'resource' cannot be nested. If you need nested routes you have to define separately parent resource and child resource. following code spinet may help you

class Book < ActiveRecord::Base
  has_many :chapter
  accepts_nested_attributes_for :chapters
end    

class Chapter < ActiveRecord::Base
  belongs_to :book
  acts_as_tree :parent_id
end
suvankar
  • 1,548
  • 1
  • 20
  • 28
1

A)

If you have a solution for the routing and the only problem with it is that you're concerned about duplicate content issues, you could consider adding <link rel="canonical" href="..."> to the pages generated from those requests. It's not bulletproof though, as Google considers it a suggestion.

Not sure if the route globbers solution would take care of generating the URLs with parent IDs though.

B)

You don't need the parent IDs to perform the routing, correct? You just want to include them in the URLs and route those requests the same as if using the URLs like example.com/chapter1, correct?

If you'd consider a solution that's not purely at the Rails level, what about rewriting the URLs on those requests so that /:parent_id/:parent_id/:id becomes /:id before Rails processes it? That would be easier if there was a static prefix, like /articles/:parent_id/:parent_id/:id.

I imagine you'd need to write some helpers to generate the URLs with parent IDs for linking to those resources.

Duplicate Content

Either way, you'll need to generate URLs that include the parent IDs, so duplicate content issues probably aren't too likely if you only link to those resources using those URLs.

JMM
  • 26,019
  • 3
  • 50
  • 55
  • I guess I will have to go with A. Can't say I understand what you mean with B though. But you are correct, I only need parent_id for routing. The article at /parent_id/ is however an article as well. – Christoffer Apr 18 '12 at 09:28
  • Actually, I was saying that you don't need parent_id for routing, correct? You want `/:parent_id/:parent_id/:id` to route to the same article that `/:id` does now, right? If you only link to those resources with URLs that include parent IDs, it's not likely you'll have to worry about duplicate content. It seems to me that the pieces you need are 1) generating URLs with parent IDs, 2) getting those to route to the correct controller, action, and article. For #1 I'm thinking you'll need to write some helpers, unless Acts_as_tree includes methods for generating such paths. – JMM Apr 18 '12 at 11:55
  • For #2 / B, if just the final article ID is actually used in routing, you could potentially rewrite the URL before Rails even routes the request, and use resources routing on `/:id`. There may be solutions at web server (e.g. Apache mod_rewrite), Rack, and Rails level. At that point if you're still worried about duplicate content, you could redirect URLs like `/:id` (where `:id` is for an article that has parents) to `/:parent_id/:id`, but you'd have to implement some extra logic to distinguish between that case and `/:id` where `:id` is for an article that doesn't have parents. – JMM Apr 18 '12 at 11:56
0
match '*p1/*p2/*p3/.../*pn' => 'articles#show'

The ... is not literal, just define as many parameters as you need upto n.

URL:
host.com/book/chapter1
params[:p1] = 'book'
params[:p2] = 'chapter1'
params[:p3] = nil


URL:
host.com/book/chapter1/section2/sentence4
params[:p1] = 'book'
params[:p2] = 'chapter1'
params[:p3] = 'section2'
params[:p4] = 'sentence4'
params[:p5] = nil

That'd have to be your LAST route.

I think it would also make any catchall routes inoperable, but they're now commented out in the default routes.rb in Rails 3, If you use them, you'd have to manually specify all routes normally handled by the old style catchall routes.

And, if you have a controller named articles, you could never have a book titled 'articles' same with all your controllers, To be safe you probably have to rename all your controllers, i.e articles becomes X_articles. You could never have a book call X_articles then, and so on....

Totally untested.

RadBrad
  • 7,234
  • 2
  • 24
  • 17
  • Thanks, but I can't do this because there is not a set number of levels. Some would be host.com/article and some would be host.com/parent-article/article – Christoffer Apr 18 '12 at 09:26
0

What you're looking to do is use Rails for something it isn't made for. No matter what answer you get here, it either won't be RESTful, DRY, or make sense to be used with Active Record. Consider restructuring your idea, or bring your application to another platform if it's not too late.

Community
  • 1
  • 1
Kyle Macey
  • 8,074
  • 2
  • 38
  • 78
  • I'd say it's not RESTful the way Rails implements REST, and it is a bastardization in some ways, as long as he adheres to the basic principals of REST (i.e. GET doesn't modify a resource), he's being RESTful enough to gain some benefit, (i.e. a load balancer can direct his URL's to a read only replication of the database.) I don't think he's over nesting, he's not nesting his resources, he's just trying to get his URL's to look a certain way. I think abandoning rails in this case isn't necessary. I think maybe he should just abandon the idea of coercing the URLs to look 'tree-like' – RadBrad Apr 15 '12 at 20:32
  • I can't see how this would be such a difficult thing to do. All blogs are made up this way and it makes perfect sense that the url's reflect the internal tree structure of the articles. – Christoffer Apr 18 '12 at 09:25