module ActiveScaffold::Finder

Constants

NULL_COMPARATORS
NUMERIC_COMPARATORS
STRING_COMPARATORS

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 258
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 == 'PostgreSQL' ? 'ILIKE' : 'LIKE'
end

Protected Instance Methods

active_scaffold_conditions() click to toggle source
# File lib/active_scaffold/finder.rb, line 265
def active_scaffold_conditions
  @active_scaffold_conditions ||= []
end
active_scaffold_habtm_joins() click to toggle source
# File lib/active_scaffold/finder.rb, line 285
def active_scaffold_habtm_joins
  @active_scaffold_habtm_joins ||= []
end
active_scaffold_includes() click to toggle source
# File lib/active_scaffold/finder.rb, line 279
def active_scaffold_includes
  ActiveSupport::Deprecation.warn "active_scaffold_includes doesn't exist anymore, use active_scaffold_preload, active_scaffold_outer_joins or active_scaffold_references"
  active_scaffold_preload
end
active_scaffold_includes=(value) click to toggle source
# File lib/active_scaffold/finder.rb, line 274
def active_scaffold_includes=(value)
  ActiveSupport::Deprecation.warn "active_scaffold_includes doesn't exist anymore, use active_scaffold_preload, active_scaffold_outer_joins or active_scaffold_references"
  self.active_scaffold_preload = value
end
active_scaffold_outer_joins() click to toggle source
# File lib/active_scaffold/finder.rb, line 290
def active_scaffold_outer_joins
  @active_scaffold_outer_joins ||= []
end
active_scaffold_preload() click to toggle source
# File lib/active_scaffold/finder.rb, line 270
def active_scaffold_preload
  @active_scaffold_preload ||= []
end
active_scaffold_references() click to toggle source
# File lib/active_scaffold/finder.rb, line 295
def active_scaffold_references
  @active_scaffold_references ||= []
end
all_conditions() click to toggle source
# File lib/active_scaffold/finder.rb, line 312
def all_conditions
  [
    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_session_storage['conditions'] # embedding conditions (weaker constraints)
  ].reject(&:blank?)
end
append_to_query(relation, options) click to toggle source
# File lib/active_scaffold/finder.rb, line 432
def append_to_query(relation, options)
  options.assert_valid_keys :where, :select, :having, :group, :reorder, :limit, :offset, :joins, :outer_joins, :includes, :lock, :readonly, :from, :conditions, :preload, (:references if Rails::VERSION::MAJOR >= 4)
  relation = options.reject { |_, v| v.blank? }.inject(relation) do |rel, (k, v)|
    k == :conditions ? apply_conditions(rel, *v) : rel.send(k, v)
  end
  if options[:outer_joins].present?
    if Rails::VERSION::MAJOR >= 4
      relation.distinct_value = true
    else
      relation = relation.uniq
    end
  end
  relation
end
apply_conditions(relation, *conditions) click to toggle source
# File lib/active_scaffold/finder.rb, line 458
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 415
def calculate_last_modified(query)
  return unless conditional_get_support? && query.klass.columns_hash['updated_at']
  @last_modified = query.maximum(:updated_at)
end
calculate_query() click to toggle source
# File lib/active_scaffold/finder.rb, line 420
def calculate_query
  conditions = all_conditions
  includes = active_scaffold_config.list.count_includes
  includes ||= active_scaffold_references unless conditions.blank?
  outer_joins = active_scaffold_outer_joins
  outer_joins += includes if includes
  primary_key = active_scaffold_config.model.primary_key
  subquery = append_to_query(beginning_of_chain, :conditions => conditions, :joins => joins_for_finder, :outer_joins => outer_joins, :select => active_scaffold_config.columns[primary_key].field)
  subquery = subquery.unscope(:order) if Rails::VERSION::MAJOR >= 4
  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 300
def conditions_for_collection
end
count_items(query, find_options = {}, count_includes = nil) click to toggle source
# File lib/active_scaffold/finder.rb, line 367
def count_items(query, find_options = {}, count_includes = nil)
  count_includes ||= find_options[:includes] unless find_options[:conditions].blank?
  options = find_options.reject { |k, _| [:select, :reorder].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 308
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 330
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 383
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.where(nil) # 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
  if options[:sorting] && options[:sorting].sorts_by_method?
    pager = ::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
    pager = ::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 340
def finder_options(options = {})
  search_conditions = all_conditions
  full_includes = (active_scaffold_references.blank? ? nil : active_scaffold_references)

  # create a general-use options array that's compatible with Rails finders
  finder_options = {
    :reorder => options[:sorting].try(:clause),
    :conditions => search_conditions,
    :joins => joins_for_finder,
    :outer_joins => active_scaffold_outer_joins,
    :preload => active_scaffold_preload,
    :includes => full_includes,
    :select => options[:select]
  }
  if Rails::VERSION::MAJOR >= 4
    if options[:sorting].try(:sorts_by_sql?)
      options[:sorting].each do |col, _|
        finder_options[:outer_joins] << col.includes if col.includes.present?
      end
    end
    finder_options.merge!(:references => active_scaffold_references)
  end

  finder_options.merge! custom_finder_options
  finder_options
end
id_condition() click to toggle source
# File lib/active_scaffold/finder.rb, line 323
def id_condition
  {active_scaffold_config.model.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 304
def joins_for_collection
end
joins_for_finder() click to toggle source
# File lib/active_scaffold/finder.rb, line 447
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 469
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.downcase == 'desc'
  collection
end