Sha256: e87afef2a6e3e7e075e4f0c4e64442f24593fb779c42dc72657f39cb6a06170f

Contents?: true

Size: 1.64 KB

Versions: 28

Compression:

Stored size: 1.64 KB

Contents

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

28 entries across 28 versions & 1 rubygems

Version Path
renalware-core-2.0.8 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.7 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.5 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.4 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.3 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.2 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.1 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc13 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc11 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc10 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc9 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc8 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc7 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc6 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc5 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc4 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc3 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.rc1 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.0.pre.beta12 app/models/concerns/renalware/ordered_set_scope.rb