I have a "page" model, and I want to be able access those pages with a
URL like: 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.
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.
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 Wayne <rails-mailing-l...@andreas-s.net>
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.
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...
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.
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.
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 = '<p>Please use the search box above</p>'
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.