Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect from /:id to /:friendly_id

Is is possible to force a 301 redirect when someone attempts to browse to a page using the old /:id URL, rather than than the preferred /:friendly_id link?

Apparently such redirections help to tell Google that you have updated the link.. so it stops displaying the old non-friendly link.

like image 683
Abram Avatar asked Feb 16 '14 23:02

Abram


2 Answers

While James Chevalier's answer is correct, you can extract this method to the ApplicationController in order to use with any model that uses FriendlyId:

def redirect_resource_if_not_latest_friendly_id(resource)
  # This informs search engines with a 301 Moved Permanently status code that
  # the show should now be accessed at the new slug. Otherwise FriendlyId
  # would make the show accessible at all previous slugs.
  if resource.friendly_id != params[:id]
    redirect_to resource, status: 301
  end
end

As you can see it's also unnecessary to pass a specific action key to redirect_to. Passing a Rails model to redirect_to will automatically attempt to access the show action on the associated collection resource route (assuming it's set up that way). That also means it's unnecessary to pass an id key since FriendlyId always returns the latest slug in the model's #to_param.

Not being a huge fan of unless (confusing semantics) I tend to shy away from it but that's more my personal preference.

like image 113
Olivier Lacan Avatar answered Oct 22 '22 09:10

Olivier Lacan


With the latest version of friendly_id (5.0.3 at the time of writing this answer) and Rails 4, I do this in the controller:

class ItemsController < ApplicationController
  before_action :set_item, only: [:show, :edit, :update, :destroy]

  ...

  private

  def set_item
    @item = Item.friendly.find(params[:id])
    redirect_to action: action_name, id: @item.friendly_id, status: 301 unless @item.friendly_id == params[:id]
  end
end

Here's a description of the redirect_to line, broken down piece by piece:

  • action: action_name retains the action that you're connecting to (which can be show, edit, update, or destroy based on the before_action that's in place) so that if you're accessing /items/1/edit you will be redirected to /items/pretty-url/edit
  • id: @item.friendly_id ensures that the URL you're being redirected to is the pretty URL
  • status: 301 sets the redirect to the status of 301, for SEO
  • unless @item.friendly_id == params[:id] makes sure that we're not redirecting people who access @item through its pretty URL
like image 34
James Chevalier Avatar answered Oct 22 '22 08:10

James Chevalier