lib/wolf_core/utils/friendly_model_id.rb
# frozen_string_literal: true # Steps to use this module: # 1. Create a migration to add the friendly_id column to your model. # 2. Include the WolfCore::FriendlyModelId in your model. # 3. Implement the friendly_id_candidates method in your model. # # Example: # # class MyModel < ApplicationRecord # include WolfCore::FriendlyModelId # # def friendly_id_candidates # [:fullname, :address] # end # end # # This will generate a friendly_id based on the fullname field. # If the fullname is not unique, it will attempt to use the address field instead. # If neither can be used to generate a unique friendly_id, it will append the id to # the value of the first field name in the array returned by the friendly_id_candidates # method, which is fullname in this case. module WolfCore module FriendlyModelId extend ActiveSupport::Concern include WolfCore::StringUtils included do raise "Model #{name} does not have a friendly_id column" unless column_names.include?("friendly_id") before_save :set_friendly_id end class_methods do def by_friendly_id(friendly_id) find_by(friendly_id: friendly_id) end end def set_friendly_id return if friendly_id.present? self.friendly_id = generate_friendly_id end def generate_friendly_id friendly_id = find_unique_friendly_id return friendly_id if friendly_id.present? default_candidate = Array(friendly_id_candidates_array.first) + [:id] convert_candidate_to_friendly_id(default_candidate) end def find_unique_friendly_id friendly_id_candidates_array.each do |candidate| friendly_id = convert_candidate_to_friendly_id(candidate) return friendly_id if friendly_id.present? && !friendly_id_used?(friendly_id) end nil end def friendly_id_candidates [:id] end def friendly_id_candidates_array Array(friendly_id_candidates) end def convert_candidate_to_friendly_id(candidate) candidate = Array(candidate) candidate.map!(&:to_sym).uniq! candidate.map do |field| field_value = send(field) parse_field_value(field_value) end.join("-") end def friendly_id_used?(friendly_id) self.class.where.not(id: id).find_by(friendly_id: friendly_id).present? end def parse_field_value(field_value) field_value = to_kebab_case(field_value) remove_non_alphanumeric_chars(field_value, exceptions: "-") end end end