norman/friendly_id-globalize

Issue with non-translatable models

Closed this issue · 1 comments

Gem version: friendly_id-globalize (~> 1.0.0.alpha3)
Ruby version: 2.3.0
Rails version: 5.1

I'm making use of the :history plugin in a bunch of translatable models but also in a couple of non-translatable models like User.

class User < ApplicationRecord
        extend FriendlyId
        friendly_id :full_name, use: [:slugged, :history]
        ...
end

For some reason my User model responds to :translations which causes the friendly_id-globalize to take over the history functionality. I needed to patch a few finder methods to make it work.

Instead of respond_to?(:translations) it is better to use respond_to?(:translation_class).
I also found the need to override the create_slug method to check if the model is making use of Globalize.

You might want to change the exists_by_friendly_id?(id) method too because you are calling "super" on a non existing method. Because the Finder methods are included, they cannot be called with "super" and you must copy the method over from the original gem. You did it for create_slug but forgot to do it for exists_by_friendly_id?(id)

People who are having the same issues can add this monkey patch to their initializers untill the issues are fixed:

module FriendlyId
  module History
    module FinderMethods
      include ::FriendlyId::FinderMethods

      def exists_by_friendly_id?(id)
        if respond_to?(:translation_class)
          joins(:slugs, :translations).where(translation_class.arel_table[friendly_id_config.query_field].eq(id)).exists? || joins(:slugs).where(slug_history_clause(id)).exists?
        else
          joins(:slugs).where(slug_history_clause(id)).exists?
        end
      end

      def slug_history_clause(id)
        if respond_to?(:translation_class)
          Slug.arel_table[:sluggable_type].eq(base_class.to_s).and(Slug.arel_table[:slug].eq(id)).and(Slug.arel_table[:locale].eq(::Globalize.locale))
        else
          Slug.arel_table[:sluggable_type].eq(base_class.to_s).and(Slug.arel_table[:slug].eq(id))
        end
      end
    end

    def create_slug
      if respond_to?(:translation_class)
        translations.map(&:locale).each do |locale|
          ::Globalize.with_locale(locale) {super_create_slug(locale)}
        end
      else
        super_create_slug(nil)
      end
    end
  end
end

Thanks for your code @jefvlamings
I need to pass my current location on super_create_slug because locale is mandatory on the table:

super_create_slug(current_locale)