module ActiveScaffold::Finder

Constants

DATE_COMPARATORS
DATE_RANGES
DATE_UNITS
NULL_COMPARATORS
NUMERIC_COMPARATORS
STRING_COMPARATORS
TIME_UNITS

Attributes

active_scaffold_conditions[W]
active_scaffold_habtm_joins[W]
active_scaffold_outer_joins[W]
active_scaffold_preload[W]
active_scaffold_references[W]

Public Class Methods

included(klass) click to toggle source
# File lib/active_scaffold/finder.rb, line 492
def self.included(klass)
  klass.extend ClassMethods
end
like_operator() click to toggle source
# File lib/active_scaffold/finder.rb, line 3
def self.like_operator
  @@like_operator ||= ::ActiveRecord::Base.connection.adapter_name.in?(%w[PostgreSQL PostGIS]) ? 'ILIKE' : 'LIKE'
end

Protected Instance Methods

active_scaffold_conditions() click to toggle source
# File lib/active_scaffold/finder.rb, line 499
def active_scaffold_conditions
  @active_scaffold_conditions ||= []
end
active_scaffold_embedded_conditions() click to toggle source
# File lib/active_scaffold/finder.rb, line 536
def active_scaffold_embedded_conditions
  params_hash active_scaffold_embedded_params[:conditions]
end
active_scaffold_habtm_joins() click to toggle source
# File lib/active_scaffold/finder.rb, line 509
def active_scaffold_habtm_joins
  @active_scaffold_habtm_joins ||= []
end
active_scaffold_outer_joins() click to toggle source
# File lib/active_scaffold/finder.rb, line 514
def active_scaffold_outer_joins
  @active_scaffold_outer_joins ||= []
end
active_scaffold_preload() click to toggle source
# File lib/active_scaffold/finder.rb, line 504
def active_scaffold_preload
  @active_scaffold_preload ||= []
end
active_scaffold_references() click to toggle source
# File lib/active_scaffold/finder.rb, line 519
def active_scaffold_references
  @active_scaffold_references ||= []
end
all_conditions(include_id_condition = true) click to toggle source
# File lib/active_scaffold/finder.rb, line 540
def all_conditions(include_id_condition = true)
  [
    (id_condition if include_id_condition),       # for list with id (e.g. /users/:id/index)
    active_scaffold_conditions,                   # from the search modules
    conditions_for_collection,                    # from the dev
    conditions_from_params,                       # from the parameters (e.g. /users/list?first_name=Fred)
    conditions_from_constraints,                  # from any constraints (embedded scaffolds)
    active_scaffold_embedded_conditions           # embedding conditions (weaker constraints)
  ].reject(&:blank?)
end
append_to_query(relation, options) click to toggle source
# File lib/active_scaffold/finder.rb, line 665
def append_to_query(relation, options)
  options.assert_valid_keys :where, :select, :having, :group, :reorder, :order, :limit, :offset,
                            :joins, :left_joins, :left_outer_joins, :includes, :lock, :readonly,
                            :from, :conditions, :preload, :references
  relation = options.reject { |_, v| v.blank? }.inject(relation) do |rel, (k, v)|
    k == :conditions ? apply_conditions(rel, *v) : rel.send(k, v)
  end
  relation.distinct_value = true if options[:left_outer_joins].present? || options[:left_joins].present?
  relation
end
apply_conditions(relation, *conditions) click to toggle source
# File lib/active_scaffold/finder.rb, line 687
def apply_conditions(relation, *conditions)
  conditions.reject(&:blank?).inject(relation) do |rel, condition|
    if condition.is_a?(Array) && !condition.first.is_a?(String) # multiple conditions
      apply_conditions(rel, *condition)
    else
      rel.where(condition)
    end
  end
end
calculate_last_modified(query) click to toggle source
# File lib/active_scaffold/finder.rb, line 648
def calculate_last_modified(query)
  return unless conditional_get_support? && ActiveScaffold::OrmChecks.columns_hash(query.klass)['updated_at']
  @last_modified = query.maximum(:updated_at)
end
calculate_query(id_condition = true) click to toggle source
# File lib/active_scaffold/finder.rb, line 653
def calculate_query(id_condition = true)
  conditions = all_conditions(id_condition)
  includes = active_scaffold_config.list.count_includes
  includes ||= active_scaffold_references if conditions.present?
  left_joins = active_scaffold_outer_joins
  left_joins += includes if includes
  primary_key = active_scaffold_config.primary_key
  subquery = append_to_query(beginning_of_chain, :conditions => conditions, :joins => joins_for_finder, :left_joins => left_joins, :select => active_scaffold_config.columns[primary_key].field)
  subquery = subquery.unscope(:order)
  active_scaffold_config.model.where(primary_key => subquery)
end
conditions_for_collection() click to toggle source

Override this method on your controller to define conditions to be used when querying a recordset (e.g. for List). The return of this method should be any format compatible with the :conditions clause of ActiveRecord::Base‘s find.

# File lib/active_scaffold/finder.rb, line 525
def conditions_for_collection; end
count_items(query, find_options = {}, count_includes = nil) click to toggle source
# File lib/active_scaffold/finder.rb, line 599
def count_items(query, find_options = {}, count_includes = nil)
  count_includes ||= find_options[:includes] if find_options[:conditions].present?
  options = find_options.reject { |k, _| %i[select reorder order].include? k }
  # NOTE: we must use includes in the count query, because some conditions may reference other tables
  options[:includes] = count_includes

  count = append_to_query(query, options).count

  # Converts count to an integer if ActiveRecord returned an OrderedHash
  # that happens when find_options contains a :group key
  count = count.length if count.is_a?(Hash)
  count
end
custom_finder_options() click to toggle source

Override this method on your controller to provide custom finder options to the find() call. The return of this method should be a hash.

# File lib/active_scaffold/finder.rb, line 532
def custom_finder_options
  {}
end
find_if_allowed(id, security_options, klass = beginning_of_chain) click to toggle source

returns a single record (the given id) but only if it’s allowed for the specified security options. security options can be a hash for authorized_for? method or a value to check as a :crud_type accomplishes this by checking model.#{action}_authorized?

# File lib/active_scaffold/finder.rb, line 558
def find_if_allowed(id, security_options, klass = beginning_of_chain)
  record = klass.find(id)
  security_options = {:crud_type => security_options.to_sym} unless security_options.is_a? Hash
  raise ActiveScaffold::RecordNotAllowed, "#{klass} with id = #{id}" unless record.authorized_for? security_options
  record
end
find_page(options = {}) click to toggle source

returns a Paginator::Page (not from ActiveRecord::Paginator) for the given parameters See finder_options for valid options

# File lib/active_scaffold/finder.rb, line 615
def find_page(options = {})
  options.assert_valid_keys :sorting, :per_page, :page, :count_includes, :pagination, :select
  options[:per_page] ||= 999_999_999
  options[:page] ||= 1

  find_options = finder_options(options)
  query = beginning_of_chain
  query = query.where(nil) if active_scaffold_config.active_record? # where(nil) is needed because we need a relation

  # NOTE: we must use :include in the count query, because some conditions may reference other tables
  if options[:pagination] && options[:pagination] != :infinite
    count = count_items(query, find_options, options[:count_includes])
  end

  query = append_to_query(query, find_options)
  # we build the paginator differently for method- and sql-based sorting
  pager = if options[:sorting]&.sorts_by_method?
            ::Paginator.new(count, options[:per_page]) do |offset, per_page|
              calculate_last_modified(query)
              sorted_collection = sort_collection_by_column(query.to_a, *options[:sorting].first)
              sorted_collection = sorted_collection.slice(offset, per_page) if options[:pagination]
              sorted_collection
            end
          else
            ::Paginator.new(count, options[:per_page]) do |offset, per_page|
              query = append_to_query(query, :offset => offset, :limit => per_page) if options[:pagination]
              calculate_last_modified(query)
              query
            end
          end
  pager.page(options[:page])
end
finder_options(options = {}) click to toggle source

valid options may include:

  • :sorting - a Sorting DataStructure (basically an array of hashes of field => direction,

    e.g. [{:field1 => 'asc'}, {:field2 => 'desc'}]).
    please note that multi-column sorting has some limitations: if any column in a multi-field
    sort uses method-based sorting, it will be ignored. method sorting only works for single-column sorting.
  • :per_page

  • :page

# File lib/active_scaffold/finder.rb, line 572
def finder_options(options = {})
  search_conditions = all_conditions

  sorting = options[:sorting]&.clause((grouped_columns_calculations if grouped_search?))
  sorting = sorting.map(&Arel.method(:sql)) if sorting && active_scaffold_config.active_record?
  # create a general-use options array that's compatible with Rails finders
  finder_options = {
    :reorder => sorting,
    :conditions => search_conditions
  }
  if active_scaffold_config.mongoid?
    finder_options[:includes] = [active_scaffold_references, active_scaffold_preload].compact.flatten.uniq.presence
  else
    finder_options.merge!(
      :joins => joins_for_finder,
      :left_joins => active_scaffold_outer_joins,
      :preload => active_scaffold_preload,
      :includes => active_scaffold_references.presence,
      :references => active_scaffold_references.presence,
      :select => options[:select]
    )
  end

  finder_options.merge! custom_finder_options
  finder_options
end
id_condition() click to toggle source
# File lib/active_scaffold/finder.rb, line 551
def id_condition
  {active_scaffold_config.primary_key => params[:id]} if params[:id]
end
joins_for_collection() click to toggle source

Override this method on your controller to define joins to be used when querying a recordset (e.g. for List). The return of this method should be any format compatible with the :joins clause of ActiveRecord::Base‘s find.

# File lib/active_scaffold/finder.rb, line 529
def joins_for_collection; end
joins_for_finder() click to toggle source
# File lib/active_scaffold/finder.rb, line 676
def joins_for_finder
  case joins_for_collection
  when String
    [joins_for_collection]
  when Array
    joins_for_collection
  else
    []
  end + active_scaffold_habtm_joins
end
sort_collection_by_column(collection, column, order) click to toggle source

TODO: this should reside on the column, not the controller

# File lib/active_scaffold/finder.rb, line 698
def sort_collection_by_column(collection, column, order)
  sorter = column.sort[:method]
  collection = collection.sort_by do |record|
    value = sorter.is_a?(Proc) ? record.instance_eval(&sorter) : record.instance_eval(sorter.to_s)
    value = '' if value.nil?
    value
  end
  collection.reverse! if order.casecmp('DESC').zero?
  collection
end