Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails using routes.rb to redirect old URLs

I have an old site built in Coldfusion, a new site built in Rails. I would like to redirect the old URLs to the new URLs. I'm not sure if routes is the way to go or not (I'm a noob). The URLs will be very similar. This should be easy but I'm not sure of the best method.

Old URL:

mysite.com/this-is-the-slug-right-here/

New URL:

mysite.com/blog/this-is-the-slug-right-here

Here is the issue, I have 3 "content types". The old site url didn't make a distinction between the content types. The new Rails site has a controller for each of the content types: Blog, Photo, Mobile Photo.

So in the example above /blog/ is the controller (content type) and this-is-the-slug-right-here is the permalink or slug for the content. Which I am getting like this:

@content = Content.where(:permalink => params[:id]).first

Should I be using routes.rb, or do I need some kind of catch-all script? Any help in getting me pointed in the right direction would be greatly appreciated.


Edit to further clarify

Here is a blog post: http://jyoseph.com/treadmill-desk-walk-this-way/

The new URL for this would be /blog/treadmill-desk-walk-this-way because it is a content type of blog.

And a photo post: http://jyoseph.com/berries/

The new URL for this would be /photos/berries because it is a content type of photo.

The content type is an attribute on the content model, stored in the attribute content_type.


Here's my routes.rb file:

resources :contents
match 'mophoblog/:id', :to => 'mophoblog#show'
match 'photos/:id', :to => 'photos#show'
match 'blog/:id', :to => 'blog#show'

root :to => "index#index"   
match ':controller(/:action(/:id(.:format)))'

Got it using @mark's answer, here's what I ended up with.

in my routes.rb

match ':id' => 'contents#redirect',  :via => :get, :as => :id

in my contents controller:

def redirect
  @content = Content.where(:permalink => params[:id]).first
  if @content.content_type.eql?('Photo')
    redirect_to "/photos/#{@content.permalink}", :status => :moved_permanently   
  elsif @content.content_type.eql?('Blog')
    redirect_to "/blog/#{@content.permalink}", :status => :moved_permanently   
  elsif @content.content_type.eql?('MoPhoBlog')   
    redirect_to "/mophoblog/#{@content.permalink}", :status => :moved_permanently   
  end
end 

I'm sure this could be improved upon, specifically the way I am redirecting, but this solved my problem perfectly.

like image 533
jyoseph Avatar asked Dec 27 '10 19:12

jyoseph


2 Answers

You can't use routes.rb to do this, however it's simple enough to set up a route, get the content type and redirect.

Something like:

routes.rb
match.resources :photos
match.resources :mobile_photos
match.resources :blog
#everything_else all resource and named routes before
match ':article_id' => 'articles#redirect',  :via => :get, :as => :article_redirect

#articles_controller.rb
def redirect
  @content = Content.find params[:id]
  if @content.content_type.eql?('photo')
    redirect_to photo_path(@content), :status => :moved_permanently
  elsif @content.content_type.eql?('mobile_photo')
    redirect_to mobile_photo_path(@content), :status => :moved_permanently
  ...
end

Now it occurs to me as I write this that you probably only want one controller for all this?

like image 77
mark Avatar answered Sep 20 '22 08:09

mark


Just thought people might be interested of a solution to do a more general redirect:

redirector = lambda do |env|
  path = env['action_dispatch.request.path_parameters'][:path]
  redirect("/new-url-base#{path}").call(env)
end

match 'old-url-base:path' => redirector, :constraints => {:path => /.*/}

redirect() just returns a simple rack app that returns the redirect headers, so wrapping it in a lambda allows you to change the arguments to it. It'd probably be better for maintenance to wrap it up in an object instead:

match 'old-url-base:path' => Redirector.new("new-url-base", :path), :constraints => {:path => /.*/}
like image 21
Matt Avatar answered Sep 22 '22 08:09

Matt