Sha256: 092c7adaaac9de02ff1a2048120e4ffe3358aed7a25e0118ce2ae0af92029f66

Contents?: true

Size: 1.68 KB

Versions: 110

Compression:

Stored size: 1.68 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(Arel.sql("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

110 entries across 110 versions & 1 rubygems

Version Path
renalware-core-2.1.1 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.1.0 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.167 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.166 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.165 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.164 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.163 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.162 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.161 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.160 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.159 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.158 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.157 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.156 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.155 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.153 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.152 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.151 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.149 app/models/concerns/renalware/ordered_set_scope.rb
renalware-core-2.0.148 app/models/concerns/renalware/ordered_set_scope.rb