Forum: Ruby on Rails How to get a nice url hierarchy with slugs and acts_as_tree?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
A21ac5660dd979ab72baddba8ca3ae97?d=identicon&s=25 Emmek on Rails (emmek)
on 2009-05-31 21:23
I have a model Page in my application that acts_as_tree. I want this
model to keep whole structure of website. I have some root nodes: home,
contact, articles, etc. and the possibility of adding children to them.

I want to access these pages using slugs (Page model and new/edit forms
have such attribute/field). In show action of pages controller:

    if params[:slug]
      @page = Page.find_by_slug(params[:slug])
      raise ActiveRecord::RecordNotFound, "Page not found" if @page.nil?
    else
      @page = Page.find(params[:id])
    end

And routing:

  map.connect ':slug', :controller => 'pages', :action => 'show'

Everything works well at the first level but how to access children
pages using hierarchy of the tree and slugs?

Example structure:

Home (pages/1)
Articles(pages/2)
----Article1 (pages/5)
----Article2 (pages/6)
Contact(pages/3)
About (pages/4)

I need this kind of access especially in 'Articles' node. I'd like to
access several article using mydomain.com/articles_slug/article1_slug.

What is the nice way to do it? Could you post some helpful links or
write solution? Any help appreciated.
2f874bf8757b5025918bfdb32f66985b?d=identicon&s=25 Julien ramel (jujudellago)
on 2009-10-01 18:48
Hi Emmek,

I never found anything really convincing to handle that, but facing the
same problem I found some workaround.

So first to get a slug, I use the plugin "ActsAsUrlParam"
http://github.com/caring/acts_as_url_param

I use it on a page "model" that uses a custom acts_as_tree  (with dotted
ids, pretty convenient to boost performances)
http://github.com/xavier/acts-as-tree-with-dotted-ids

Then I created special routes (yeah, to use with caution, I wanted to
avoid the "/pages/" prefix )
<code>
map.resources :pages
map.page_first_level '/:slug.:format',
:controller=>:pages,:action=>:show
map.page_second_level '/:parent_slug/:slug.:format',
:controller=>:pages,:action=>:show
map.page_third_level '/:ancestor_slug/:parent_slug/:slug.:format',
:controller=>:pages,:action=>:show
</code>


finally in my page helper
<code>
module PagesHelper
  def smart_page_path(page,format=nil)
    case page.depth
    when 0
      page_first_level_path(page.slug,:format=>format)
    when 1
      page_second_level_path(page.parent.slug,page.slug,:format=>format)
    when 2
      page_third_level_path(page.parent.parent.slug,
page.parent.slug,page.slug,:format=>format)
    else
      page_path(page)
    end
  end
end

</code>
it uses the page depth to generate my nice formatted URL

as result, using smart_page_path(@page)


-Home    -> /home.html
-About   -> /about.html
---History   -> /about/history.html
---Team      -> /about/team.html
-Projects    ->  /projects.html
---Global    ->  /projects/global.html
-----Ecology  -> /projects/global/ecology.html
-----Human rights  -> /projects/global/human-rights.html
---Local           -> /projects/local.html
-Contact           -> /contact.html



BUT!!
- the extra params are just meant for SEO, you can use any routes, only
the last slug will be used (/my-dummy-param/about.html)
- maybe it's not that good to use routes that starts from the root.... I
always use an "admin" namespace fro my admin sections, so I never have
much at the root anyway.


If someone has a better idea I'll be delighted to hear it.
Dd2d775dea75b381edb1bbf0600a0907?d=identicon&s=25 Marnen Laibow-Koser (marnen)
on 2009-10-01 18:59
Emmek on Rails wrote:
> I have a model Page in my application that acts_as_tree. I want this
> model to keep whole structure of website.

Then I would strongly suggest awesome_nested_set instead of
acts_as_tree.  It makes it possible to use the DB *much* more
efficiently.

> I have some root nodes: home,
> contact, articles, etc. and the possibility of adding children to them.
>
> I want to access these pages using slugs (Page model and new/edit forms
> have such attribute/field). In show action of pages controller:
>
>     if params[:slug]
>       @page = Page.find_by_slug(params[:slug])
>       raise ActiveRecord::RecordNotFound, "Page not found" if @page.nil?
>     else
>       @page = Page.find(params[:id])
>     end
>
> And routing:
>
>   map.connect ':slug', :controller => 'pages', :action => 'show'
>
> Everything works well at the first level but how to access children
> pages using hierarchy of the tree and slugs?

I'm not sure. You might need to use a *glob route for the page path,
then do your own parsing.

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
Dd2d775dea75b381edb1bbf0600a0907?d=identicon&s=25 Marnen Laibow-Koser (marnen)
on 2009-10-01 19:02
Marnen Laibow-Koser wrote:
> Emmek on Rails wrote:
>> I have a model Page in my application that acts_as_tree. I want this
>> model to keep whole structure of website.
>
> Then I would strongly suggest awesome_nested_set instead of
> acts_as_tree.  It makes it possible to use the DB *much* more
> efficiently.

Actually, on second thought, this might be a good use case for a
materialized path in the DB.  Then you could just do find_by_path to
retrieve any page at any depth.


Best,
--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
This topic is locked and can not be replied to.