module AutocompleteFor::ClassMethods

Public Instance Methods

autocomplete_for(association, field, options = {}, &block) click to toggle source
# File lib/autocomplete_for/autocomplete_for.rb, line 9
def autocomplete_for(association, field, options = {}, &block)
  allow_nil = options[:allow_nil] || false
  validate :"validate_#{association}_by_#{field}"
  before_validation :"associate_#{association}_by_#{field}"
  instance_variable_set(:"@#{association}_#{field}_allow_nil", allow_nil)

  # method to set the name of the entity to autocomplete
  # def customer_name=(name)
  #   @customer_name = name
  # end
  define_method(:"#{association}_#{field}=") do |name|
    instance_variable_set(:"@#{association}_#{field}", name)
  end

  # method to retrieve the name of the entity to autocomplete
  # def customer_name
  #   self.customer_to.name : @customer_name
  # end
  define_method(:"#{association}_#{field}") do
    send(association.to_sym) ? send(association.to_sym).send(field.to_sym) : instance_variable_get(:"@#{association}_#{field}")
  end

  # Validation method to make sure the autocompleted name resolves to an actual entity
  # def validate_customer_by_name
  #   return unless @customer_name
  #   return if self.customer
  #   return if @@customer_name_allow_nil && @customer_name == ""
  #
  #   self.errors.add :customer_name, "#{@customer_name} does not exist"
  # end
  define_method(:"validate_#{association}_by_#{field}") do
    return unless instance_variable_get(:"@#{association}_#{field}")
    return if send(association.to_sym)
    return if self.class.instance_variable_get(:"@#{association}_#{field}_allow_nil") && instance_variable_get(:"@#{association}_#{field}") == ""

    errors.add(:"#{association}_#{field}", :does_not_exist)
  end

  # Resolve the autocompleted name to an actual entity
  # def autocomplete_find_customer_by_name
  #   if self.site
  #     self.customer = self.site.floor_locations.find(:first, :include => :location, :conditions => {:'locations.name' => @customer_name})
  #   end
  # end
  define_method(:"autocomplete_find_#{association}_by_#{field}", block)

  # def associate_customer_by_name
  #   return unless @customer_name
  #
  #   if @customer_name == ''
  #     self.customer = nil
  #     return
  #   end
  #
  #   autocomplete_find_customer_by_name
  # end
  define_method(:"associate_#{association}_by_#{field}") do
    return unless instance_variable_get(:"@#{association}_#{field}")

    if instance_variable_get(:"@#{association}_#{field}") == ""
      send(:"#{association}=", nil)
      return
    end

    send(:"autocomplete_find_#{association}_by_#{field}")
  end

  # set up validation on association in case the customer_name isn't set
  error_fields_name = :"@#{association}_autocomplete_error_fields"
  error_fields = instance_variable_get(error_fields_name) || []
  error_fields << :"#{association}_#{field}"

  instance_variable_set(error_fields_name, error_fields)

  unless allow_nil
    # we must make sure that the validate_by_customer validation runs
    # after ALL validations on autocomplete fields
    # skip_callback :validate, :by, :"#{association}"

    validate :"validate_by_#{association}"

    unless instance_methods.include?("validate_by_#{association}")

      # def validate_by_customer
      #   self.errors.add_on_blank(:customer) unless @@customer_autocomplete_error_fields.any? {|ef| self.errors[ef]}
      # end
      define_method(:"validate_by_#{association}") do
        return if self.class.instance_variable_get(error_fields_name).any? { |ef| errors[ef].any? }
        return unless send(:read_attribute_for_validation, association.to_sym).blank?

        errors.add(association.to_sym, :blank, options)
      end
    end
  end
end