module OrderAsSpecified
This module adds the ability to query an ActiveRecord class for results from the database in an arbitrary order, without having to store anything extra in the database. Simply `extend` it into your class and then you can use the `order_as_specified` class method.
Constants
- VERSION
Public Instance Methods
order_as_specified(hash)
click to toggle source
@param hash [Hash] the ActiveRecord arguments hash @return [ActiveRecord::Relation] the objects, ordered as specified
# File lib/order_as_specified.rb, line 13 def order_as_specified(hash) distinct_on = hash.delete(:distinct_on) case_insensitive = hash.delete(:case_insensitive) params = extract_params(hash) return all if params[:values].empty? table = Arel::Table.new(params[:table]) node = Arel::Nodes::Case.new params[:values].each_with_index do |value, index| attribute = table[params[:attribute]] condition = if value.is_a?(Range) if value.first >= value.last raise OrderAsSpecified::Error, "Range needs to be increasing" end attribute.between(value) elsif case_insensitive attribute.matches(value) else attribute.eq(value) end node.when(condition).then(index) end node.else(node.conditions.size) scope = order(Arel::Nodes::Ascending.new(table.grouping(node))) if distinct_on distinct = Arel::Nodes::DistinctOn.new(node) table_alias = connection.quote_table_name(table.name) scope = scope.select(Arel.sql("#{distinct.to_sql} #{table_alias}.*")) end scope end
Private Instance Methods
extract_params(hash, table = table_name)
click to toggle source
Recursively search through the hash to find the last elements, which indicate the name of the table we want to condition on, the attribute name, and the attribute values for ordering by. @param table [String/Symbol] the name of the table, default: the class table @param hash [Hash] the ActiveRecord-style arguments, such as:
{ other_objects: { id: [1, 5, 3] } }
# File lib/order_as_specified.rb, line 61 def extract_params(hash, table = table_name) unless hash.size == 1 raise OrderAsSpecified::Error, "Could not parse params" end key, val = hash.first if val.is_a? Hash extract_params(hash[key], key) else { table: table, attribute: key, values: val } end end