# Database driven root level routing, like /some\_page\_name

**URL:** <https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521>\
**Category:** Rails\
**Created:** [May 13, 2008, 11:01pm UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521 "2008-05-13T23:01:42Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![squeegy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/dec6dc/32.png) [@squeegy](https://www.ruby-forum.com/u/squeegy)\
**Post date:** [May 13, 2008, 11:01pm UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521/1 "2008-05-13T23:01:42Z")

</div>

I have a “page” model, and I want to be able access those pages with a  
URL like: [http://foo.com/my\_page\_name](http://foo.com/my_page_name)

Just wondering if there is a best practice for this. I have avoided it  
this far because I didnt want these routes conflicting with the routes  
of the rest of the app.

I see 2 ways off the top of my head.

1. Use a low priority route that will match any single parameter URL.  
This route will call the page controller and show the page. Since its  
low priority, it only triggers if no other routes match. This seems  
like it might make 404’s a bit messy to handle since I’m basically  
creating a catch all that shouldn’t always work.

2. Ask my Page model for a regex to match the id parameter with. This  
would be a cleaner solution in the routes themselves, but I don’t like  
the idea of hitting the database to check routing.

Any comments or ideas?

---

<div class="post-metadata">

**Author:** ![squeegy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/dec6dc/32.png) [@squeegy](https://www.ruby-forum.com/u/squeegy)\
**Post date:** [May 14, 2008, 2:52am UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521/2 "2008-05-14T02:52:07Z")

</div>

Could you accept the slightly-less-beautiful:

[http://foo.com/pages/my\_page\_name](http://foo.com/pages/my_page_name)?

If so, you could override to\_param on your Page class and have it  
return the page name. If you do that then the Pages controller can  
use Page.find\_by\_name to show the page.

On May 13, 5:01 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![squeegy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/dec6dc/32.png) [@squeegy](https://www.ruby-forum.com/u/squeegy)\
**Post date:** [May 14, 2008, 3:17am UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521/3 "2008-05-14T03:17:26Z")

</div>

AndyV wrote:

> Could you accept the slightly-less-beautiful:
> 
> [http://foo.com/pages/my\_page\_name](http://foo.com/pages/my_page_name)?
> 
> If so, you could override to\_param on your Page class and have it  
> return the page name. If you do that then the Pages controller can  
> use Page.find\_by\_name to show the page.
> 
> On May 13, 5:01 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

I have that now. The problem is that my client keeps wanting shorter at  
the root level URLs for print in ads and what not. Easier to type and  
remember.

---

<div class="post-metadata">

**Author:** ![squeegy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/dec6dc/32.png) [@squeegy](https://www.ruby-forum.com/u/squeegy)\
**Post date:** [May 14, 2008, 6:31am UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521/4 "2008-05-14T06:31:58Z")

</div>

On May 13, 2008, at 6:17 PM, Alex W. wrote:

> I have that now. The problem is that my client keeps wanting  
> shorter at  
> the root level URLs for print in ads and what not. Easier to type and  
> remember.

In that case… you might suggest

[http://foo.com/xabc/my\_page\_name](http://foo.com/xabc/my_page_name)  
[http://foo.com/xbcd/my\_page\_name](http://foo.com/xbcd/my_page_name)  
[http://foo.com/xcde/my\_page\_name](http://foo.com/xcde/my_page_name)

where /x…/ can be routed based on starting with x and the rest maps  
to a specific campaign. You get a routing cop-out, but you can also  
log the request URLs to provide tracking for response to very  
specific sources. Keep the string short, but you can still get as  
detailed as making every advertising source a unique string.

Doesn’t answer your question (not much of a routes guru yet), but  
maybe there’s an opportunity to do something even more beneficial  
than planned…

– gw

---

<div class="post-metadata">

**Author:** ![squeegy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/dec6dc/32.png) [@squeegy](https://www.ruby-forum.com/u/squeegy)\
**Post date:** [May 14, 2008, 2:59pm UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521/5 "2008-05-14T14:59:31Z")

</div>

Sorry, I’d guessed that might be the case.

One other possibility… sometimes it’s easy to overlook that even  
things like the routes.rb file are just specialized ruby scripts. As  
such you can still stick code in there and dynamically create the  
routes. Something like this totally untested, off-the-top-of-my-head  
block:

Page.find(:all).each do |routed\_page|  
map.connect “/  
#{page.slug}”, :controller=\>‘pages’, :action=\>‘show’, :id=\>page.id  
end

Interested to know how/if this works but don’t have time to test it.

HTH,  
AndyV

On May 13, 9:17 pm, Alex W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![squeegy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/dec6dc/32.png) [@squeegy](https://www.ruby-forum.com/u/squeegy)\
**Post date:** [May 14, 2008, 5:59pm UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521/6 "2008-05-14T17:59:59Z")

</div>

AndyV wrote:

> Page.find(:all).each do |routed\_page|  
> map.connect “/  
> #{page.slug}”, :controller=\>‘pages’, :action=\>‘show’, :id=\>page.id  
> end

Interesting approach!

Although, I am pretty sure that routes.rb only gets evaluated when rails  
boots up, so new pages that are added would not have a route.

I did manage to come with a solution after some digging that does seem  
to work though. I added this to the bottom of my routes file:

map.page ‘:id’, :controller =\> ‘pages’, :action =\> ‘show’

Since its at the bottom it gets referenced last so it doesn’t interfere  
with other named routes. And the pages/show action will raise a  
ActiveRecord::RecordNotFound exception if the page isn’t in the  
database, which rails rescues and displays a 404. So I guess it works  
great.

Thanks for the ideas all.

---

<div class="post-metadata">

**Author:** ![squeegy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/dec6dc/32.png) [@squeegy](https://www.ruby-forum.com/u/squeegy)\
**Post date:** [May 15, 2008, 5:07am UTC](https://www.ruby-forum.com/t/database-driven-root-level-routing-like-some-page-name/137521/7 "2008-05-15T05:07:26Z")

</div>

On Tue, May 13, 2008 at 2:01 PM, Alex W.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I have a “page” model, and I want to be able access those pages with a  
> URL like: [http://foo.com/my\_page\_name](http://foo.com/my_page_name)
> 
> 1. Use a low priority route that will match any single parameter URL.  
> This route will call the page controller and show the page. Since its  
> low priority, it only triggers if no other routes match. This seems  
> like it might make 404’s a bit messy to handle since I’m basically  
> creating a catch all that shouldn’t always work.

I do something a lot like this for my app. After the normal rails  
default route, I catch everything else with my show\_page route. My  
page controllers show action checks the db for a page with the  
appropriate path and displays it - or renders my custom “not found”  
message with a status code of 404.

routes.rb

# Install the default routes as the lowest priority.

map.connect ‘:controller/:action/:id’  
map.connect ‘:controller/:action/:id.:format’

# Finally let CMS figure out what to do with fall through pages

map.show\_page ‘\*url\_parts’, :controller =\> “pages”, :action =\> “show”

pages\_controller.rb

def show  
@page = Page.find\_by\_url\_parts(params[:url\_parts])

```
respond_to do |format|
  if @page
    store_location
    response.headers['Last-Modified'] = 

```

@page.updated\_at.to\_s(:rfc822)  
format.html # show the page  
format.xml { render :xml =\> @page }  
else  
format.html {  
title = “Page Not Found”  
body = ‘

Please use the search box above

’  
render\_404( [“”], title, body)  
}  
format.xml { head :status =\> :not\_found }  
end  
end  
end

and in my application.rb controller, the render\_404 method:

def render\_404(base, title, body)  
@page = Page.find\_by\_url\_parts( base )  
@page.body = body  
@page.title = title  
render :template =\> “pages/show”, :status =\> 404  
end

render\_404 grabbing a page (the home page) is so that the styling and  
navigation stuff gets built and sent to the user.

–  
Cynthia K.
