module FriendlyId::FinderMethods

Public Instance Methods

exists?(conditions = :none) click to toggle source

Returns true if a record with the given id exists.

Calls superclass method
# File lib/friendly_id/finder_methods.rb, line 40
def exists?(conditions = :none)
  return super if conditions.unfriendly_id?
  return true if exists_by_friendly_id?(conditions)
  super
end
exists_by_friendly_id?(id) click to toggle source
# File lib/friendly_id/finder_methods.rb, line 53
def exists_by_friendly_id?(id)
  where(friendly_id_config.query_field => parse_friendly_id(id)).exists?
end
find(*args, allow_nil: false) click to toggle source

Finds a record using the given id.

If the id is “unfriendly”, it will call the original find method. If the id is a numeric string like '123' it will first look for a friendly id matching '123' and then fall back to looking for a record with the numeric id '123'.

@param [Boolean] allow_nil (default: false) Use allow_nil: true if you'd like the finder to return nil instead of raising ActivRecord::RecordNotFound

### Example

MyModel.friendly.find("bad-slug")
#=> raise ActiveRecord::RecordNotFound

MyModel.friendly.find("bad-slug", allow_nil: true)
#=> nil

Since FriendlyId 5.0, if the id is a nonnumeric string like '123-foo' it will only search by friendly id and not fall back to the regular find method.

If you want to search only by the friendly id, use {#find_by_friendly_id}. @raise ActiveRecord::RecordNotFound

Calls superclass method
# File lib/friendly_id/finder_methods.rb, line 28
def find(*args, allow_nil: false)
  id = args.first
  return super(*args) if args.count != 1 || id.unfriendly_id?
  first_by_friendly_id(id).tap { |result| return result unless result.nil? }
  return super(*args) if potential_primary_key?(id)

  raise_not_found_exception(id) unless allow_nil
rescue ActiveRecord::RecordNotFound => exception
  raise exception unless allow_nil
end
find_by_friendly_id(id) click to toggle source

Finds exclusively by the friendly id, completely bypassing original `find`. @raise ActiveRecord::RecordNotFound

# File lib/friendly_id/finder_methods.rb, line 49
def find_by_friendly_id(id)
  first_by_friendly_id(id) or raise_not_found_exception(id)
end

Private Instance Methods

first_by_friendly_id(id) click to toggle source
# File lib/friendly_id/finder_methods.rb, line 77
def first_by_friendly_id(id)
  find_by(friendly_id_config.query_field => parse_friendly_id(id))
end
parse_friendly_id(value) click to toggle source

Parse the given value to make it suitable for use as a slug according to your application's rules.

This method is not intended to be invoked directly; FriendlyId uses it internally to process a slug into string to use as a finder.

However, if FriendlyId's default slug parsing doesn't suit your needs, you can override this method in your model class to control exactly how slugs are generated.

### Example

class Person < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name_and_location

  def name_and_location
    "#{name} from #{location}"
  end

  # Use default slug, but lower case
  # If `id` is "Jane-Doe" or "JANE-DOE", this finds data by "jane-doe"
  def parse_friendly_id(slug)
    super.downcase
  end
end

@param [#to_s] value The slug to be parsed. @return The parsed slug, which is not modified by default.

# File lib/friendly_id/finder_methods.rb, line 110
def parse_friendly_id(value)
  value
end
potential_primary_key?(id) click to toggle source
# File lib/friendly_id/finder_methods.rb, line 59
def potential_primary_key?(id)
  key_type = primary_key_type
  # Hook for "ActiveModel::Type::Integer" instance.
  key_type = key_type.type if key_type.respond_to?(:type)
  case key_type
  when :integer
    begin
      Integer(id, 10)
    rescue
      false
    end
  when :uuid
    id.match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
  else
    true
  end
end
raise_not_found_exception(id) click to toggle source
# File lib/friendly_id/finder_methods.rb, line 114
def raise_not_found_exception(id)
  message = "can't find record with friendly id: #{id.inspect}"
  if ActiveRecord.version < Gem::Version.create("5.0")
    raise ActiveRecord::RecordNotFound.new(message)
  else
    raise ActiveRecord::RecordNotFound.new(message, name, friendly_id_config.query_field, id)
  end
end