Life In The Stack Trace...

TODO: <Insert clever marketing phrase here>

Sitemaps And Nested Resources Using DuckMap

I think the easiest way to explain sitemaps with nested resources is to explain the process from a high level.

When a sitemap is built:

  • The sitemap controller kicks in, builds a list of routes the sitemap should contain and loops through the routes.
  • for each route:
    • automagically determine the controller and model used for the route. if specified by the developer, use those values.
    • ask the controller for all of the attributes for the url node.
    • controller asks the model for attributes when building the actual canonical url for the node.
    • model responds by populating a Hash with key/value pairs representing the segments of a route.

Given the following configuration:

MyApp::Application.routes.draw do

  resources :books do
    resources :comments
  end

end

Would have a named route like:

book_comment GET    /books/:book_id/comments/:id(.:format)      comments#show

The mechanism used to acquire these values is: sitemapcapturesegments. You can see that the "show" action for the route has segment keys :bookid and :id. When the url is built, the Comment model is "asked" for the segment key values for the route by a call to sitemapcapturesegments. The model is passed an Array containing all of the keys required to build the url for the named route. In this case, the default behavior would be to ask the Comment model for :bookid and :id.

The following is an example of the output that could be produced:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>http://localhost:3000/books.html</loc>
    <lastmod>2013-02-20T15:46:13+00:00</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.5</priority>
  </url>
  <url>
    <loc>http://localhost:3000/books/1.html</loc>
    <lastmod>2013-02-20T15:46:13+00:00</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.5</priority>
  </url>
  <url>
    <loc>http://localhost:3000/books/1/comments/1.html</loc>
    <lastmod>2013-02-20T15:46:35+00:00</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.5</priority>
  </url>
</urlset>

If you are following Rails conventions, DuckMap should be able to pickup most nested routes. However, we are not always afforded the luxury of adhering to all conventions. Therefore, you have the option of defining segment key mappings.

class Comment < ActiveRecord::Base

  sitemap_segments book_id: :my_book_id

end

When the url is built, the model object will be asked to provide values for: :mybookid and :id and map those values back to the real :book_id and :id when the url is built.

The home page has links to all of the sitemaps and they should contain sample urls if you run: rake db:seed