Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FriendlyId and CanCanCan and redirects #1007

Open
AliOsm opened this issue Apr 30, 2023 · 0 comments
Open

FriendlyId and CanCanCan and redirects #1007

AliOsm opened this issue Apr 30, 2023 · 0 comments

Comments

@AliOsm
Copy link

AliOsm commented Apr 30, 2023

Question:

Let's say you have a model Speaker that utilizes FiendlyId gem to create unique slugs like this:

class Speaker < ApplicationRecord
  friendly_id :name, use: %i[slugged history finders]
end

And you are using CanCanCan gem to implement authorization in your application. So, in your SpeakersController you are loading and authorizing the resources like this:

class SpeakersController < ApplicationController
  load_and_authorize_resource

  # GET /speakers
  def index; end

  # GET /speakers/1
  def show; end
end

And you are using the same method to load and authorize resources in other controllers.

How you can utilize the history plugin from FiendlyId gem to redirect your old slugs like /speakers/falde-ali to new slugs like /speakers/ali-fadel when you change the speaker name, without implementing a specific method inside each controller to handle it?


Answer:

Basically, you can implement a concern inside app/controller/concerns like this:

# app/controller/concerns/slug_redirector.rb

module SlugRedirector
  extend ActiveSupport::Concern

  included do
    before_action :redirect_to_canonical_route
  end

  def redirect_to_canonical_route
    record = get_record(model)

    return if record.blank?

    canonical_path = get_canonical_path(record)

    redirect_to canonical_path, status: :moved_permanently if should_redirect?(canonical_path)
  end

  private

  def model
    controller_name.classify.constantize
  end

  def namespace
    self.class.module_parent_name&.downcase&.to_sym
  end

  def get_record(model)
    instance_variable_get("@#{model.name.underscore}")
  end

  def get_canonical_path(record)
    polymorphic_path([namespace, record])
  end

  def should_redirect?(canonical_path)
    request.path != canonical_path
  end
end

Then include it into your controllers below the load and authorization call, like this:

class SpeakersController < ApplicationController
  load_and_authorize_resource

  include SlugRedirector

  # GET /speakers
  def index; end

  # GET /speakers/1
  def show; end
end

This concern implements a redirect to the latest slug using the FriendlyId gem.

The concern includes a before_action that calls the redirect_to_canonical_route method. This method retrieves the record from the controller's instance variables, then generates a canonical path using the polymorphic_path method. If the current request path doesn't match the canonical path, the method issues a permanent redirect to the canonical path using redirect_to.

This concern provides a way to ensure that URLs with old or outdated slugs are redirected to the latest version of the URL. This can be helpful for maintaining SEO and ensuring that users are always directed to the correct page.

I hope it is helpful :)


What do you think about the approach and about adding this concern as a plugin inside FriendlyId ?.?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant