Skip to content

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

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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