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.
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?
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 => /.*/}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With