Skip to content

Short scopes and predicates (similar functionality exists in ActiveRecord::Enum). #21

@MityaLiu

Description

@MityaLiu

@albertosaurus
I'm currently using short scopes and predicates defined as ActiveSupport::Concern.
If I make a PR would you be interested in adding such functionality?
I'm asking because it'll take me a day to port this code and add specs.
It allows the following syntax:

has_enumerated :status, short_scopes: true, predicates: true
# existing => new
booking.with_status(:active) => booking.active
booking.all_except(:active) => booking.not_active
booking.status === :rejected => booking.rejected?

# Extensions for PowerEnum
module PowerEnumEnhancements
  extend ActiveSupport::Concern

  # TODO: Consider making a PR to PowerEnum
  module ClassMethods
    # Dynamically defines predicate methods from enum names
    # @param [Symbol] relation_name
    # @return [Nil]
    private def define_enum_predicates(relation_name)
      reflection = find_reflection_by_name!(relation_name)
      if enum_table_exists?(reflection)
        reflection.klass.names.each do |name|
          define_method("#{name}?") do
            public_send(reflection.name).like?(name)
          end
        end
      end
    end

    # Dynamically defines scopes from enum names
    # @param [Symbol] relation_name
    # @return [Nil]
    private def define_enum_scopes(relation_name)
      reflection = find_reflection_by_name!(relation_name)
      if enum_table_exists?(reflection)
        reflection.klass.names.each do |name|
          scope name, -> { public_send("with_#{reflection.name}", name) }
          scope "not_#{name}", -> { public_send("exclude_#{reflection.name}", name) }
        end
      end
    end

    # Finds a reflection by name
    # @param [Symbol] relation_name
    # @raise [ArgumentError]
    # @return [PowerEnum::Reflection::EnumerationReflection]
    private def find_reflection_by_name!(relation_name)
      reflection = reflect_on_all_associations(:belongs_to).find { |relation| relation.name == relation_name.to_sym }
      if reflection&.class != PowerEnum::Reflection::EnumerationReflection
        raise ArgumentError, "Relation #{relation_name} doesn't exist"
      end

      reflection
    end

    # Checks if there's a DB connection and if given table exists
    # @param [Symbol] relation_name
    # @return [Boolean]
    private def enum_table_exists?(reflection)
      connection.table_exists?(reflection.plural_name)
    rescue ActiveRecord::NoDatabaseError, PG::ConnectionBad
      false
    end
  end
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions