Sha256: 0652c2ef1f8913e5cffec6bff0937f95974b4f8e37db0daff6e15a6269721837

Contents?: true

Size: 1.67 KB

Versions: 39

Compression:

Stored size: 1.67 KB

Contents

# frozen_string_literal: true

module Renalware
  module OrderedSetScope
    extend ActiveSupport::Concern

    class_methods do
      # Produces a scope that orders a relation based on a attribue and the
      # order of the values.
      #
      # @example
      #
      # Give the relation 'qux':
      #   |id | code |
      #   | 1 | baz  |
      #   | 2 | bar  |
      #   | 3 | foo  |
      #
      # When I execute the following:
      #
      #   Qux.fixed_order_for(:code, %i(foo bar))
      #
      # Then the following set is returned:
      #   |id | code |
      #   | 3 | foo  |
      #   | 2 | bar  |
      #
      # The implementation is based on this blog post:
      # http://sqlandme.com/2013/11/18/sql-server-custom-sorting-in-order-by-clause/
      #
      def ordered_set(attribute, values)
        verified_values = verify_values(attribute, values.map(&:to_s))

        where(attribute => verified_values)
          .order("CASE #{generate_conditions(attribute, values.uniq)} END")
      end

      private

      # Verify the values exist in the database, prevents a SQL inject attack
      # when ordering, as order scopes doen't sanitize.
      #
      def verify_values(attribute, values)
        values & where(attribute => values).pluck(attribute)
      end

      # Example:
      #   Given the following:
      #     attribute: 'code'
      #     values: %w(foo bar)

      #   Then generates:
      #     WHEN code = 'foo' THEN 0
      #     WHEN code = 'bar' THEN 1
      #
      def generate_conditions(attribute, values)
        values.each_with_index.map do |value, idx|
          "WHEN #{attribute} = '#{value}' THEN '#{idx}'"
        end.join(" ")
      end
    end
  end
end

Version data entries

39 entries across 39 versions & 1 rubygems

Version Path
renalware-core-2.0.51 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.50 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.48 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.47 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.46 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.45 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.44 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.43 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.42 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.41 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.40 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.39 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.38 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.37 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.36 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.35 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.34 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.33 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.32 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.31 app/models/concerns/renalware/ordered_set_scope.rb