require "active_record" require "friendly_id/base" require "friendly_id/object_utils" require "friendly_id/configuration" require "friendly_id/finder_methods" # @guide begin # # ## About FriendlyId # # FriendlyId is an add-on to Ruby's Active Record that allows you to replace ids # in your URLs with strings: # # # without FriendlyId # http://example.com/states/4323454 # # # with FriendlyId # http://example.com/states/washington # # It requires few changes to your application code and offers flexibility, # performance and a well-documented codebase. # # ### Core Concepts # # #### Slugs # # The concept of *slugs* is at the heart of FriendlyId. # # A slug is the part of a URL which identifies a page using human-readable # keywords, rather than an opaque identifier such as a numeric id. This can make # your application more friendly both for users and search engines. # # #### Finders: Slugs Act Like Numeric IDs # # To the extent possible, FriendlyId lets you treat text-based identifiers like # normal IDs. This means that you can perform finds with slugs just like you do # with numeric ids: # # Person.find(82542335) # Person.friendly.find("joe") # # @guide end module FriendlyId autoload :History, "friendly_id/history" autoload :Slug, "friendly_id/slug" autoload :SimpleI18n, "friendly_id/simple_i18n" autoload :Reserved, "friendly_id/reserved" autoload :Scoped, "friendly_id/scoped" autoload :Slugged, "friendly_id/slugged" autoload :Finders, "friendly_id/finders" autoload :SequentiallySlugged, "friendly_id/sequentially_slugged" # FriendlyId takes advantage of `extended` to do basic model setup, primarily # extending {FriendlyId::Base} to add {FriendlyId::Base#friendly_id # friendly_id} as a class method. # # Previous versions of FriendlyId simply patched ActiveRecord::Base, but this # version tries to be less invasive. # # In addition to adding {FriendlyId::Base#friendly_id friendly_id}, the class # instance variable +@friendly_id_config+ is added. This variable is an # instance of an anonymous subclass of {FriendlyId::Configuration}. This # allows subsequently loaded modules like {FriendlyId::Slugged} and # {FriendlyId::Scoped} to add functionality to the configuration class only # for the current class, rather than monkey patching # {FriendlyId::Configuration} directly. This isolates other models from large # feature changes an addon to FriendlyId could potentially introduce. # # The upshot of this is, you can have two Active Record models that both have # a @friendly_id_config, but each config object can have different methods # and behaviors depending on what modules have been loaded, without # conflicts. Keep this in mind if you're hacking on FriendlyId. # # For examples of this, see the source for {Scoped.included}. def self.extended(model_class) return if model_class.respond_to? :friendly_id class << model_class alias_method :relation_without_friendly_id, :relation end model_class.class_eval do extend Base @friendly_id_config = Class.new(Configuration).new(self) FriendlyId.defaults.call @friendly_id_config include Model end end # Allow developers to `include` FriendlyId or `extend` it. def self.included(model_class) model_class.extend self end # Set global defaults for all models using FriendlyId. # # The default defaults are to use the `:reserved` module and nothing else. # # @example # FriendlyId.defaults do |config| # config.base :name # config.use :slugged # end def self.defaults(&block) @defaults = block if block @defaults ||= ->(config) { config.use :reserved } end # Set the ActiveRecord table name prefix to friendly_id_ # # This makes 'slugs' into 'friendly_id_slugs' and also respects any # 'global' table_name_prefix set on ActiveRecord::Base. def self.table_name_prefix "#{ActiveRecord::Base.table_name_prefix}friendly_id_" end end