module ActiveScaffold::Finder
Constants
- NullComparators
- NumericComparators
- StringComparators
Attributes
Public Class Methods
# File lib/active_scaffold/finder.rb, line 218 def self.included(klass) klass.extend ClassMethods end
Protected Instance Methods
# File lib/active_scaffold/finder.rb, line 225 def active_scaffold_conditions @active_scaffold_conditions ||= [] end
# File lib/active_scaffold/finder.rb, line 235 def active_scaffold_habtm_joins @active_scaffold_habtm_joins ||= [] end
# File lib/active_scaffold/finder.rb, line 230 def active_scaffold_includes @active_scaffold_includes ||= [] end
# File lib/active_scaffold/finder.rb, line 239 def all_conditions merge_conditions( 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) ) end
# File lib/active_scaffold/finder.rb, line 324 def append_to_query(query, options) options.assert_valid_keys :where, :select, :group, :order, :limit, :offset, :joins, :includes, :lock, :readonly, :from offset = options.delete(:offset) options.delete(:readonly) options.reject{|k, v| v.blank?}.inject(query) do |query, (k, v)| if k == :order # default ordering of model has a higher priority than current queries ordering # fix this by removing existing ordering from arel query = query.unordered query.send(:order, *v) elsif k == :limit val = [v] val << offset if offset query.send(:limit, *val) elsif k == :includes query.send(:eager, v) elsif k == :joins v.each do |j| query = query.send(:join, *j) end query elsif k == :lock query.send(:lock_style, (v == true ? :update : v)) else query.send(k, v) end end end
Returns a hash with options to count records, rejecting select and order options See finder_options
for valid options
# File lib/active_scaffold/finder.rb, line 281 def count_options(find_options = {}, count_includes = nil) count_includes ||= find_options[:includes] unless find_options[:where].nil? options = find_options.reject{|k,v| [:select, :order].include? k} options[:includes] = count_includes options end
returns a single record (the given id) but only if it’s allowed for the specified action. accomplishes this by checking model.#{action}_authorized? TODO: this should reside on the model, not the controller
# File lib/active_scaffold/finder.rb, line 252 def find_if_allowed(id, crud_type, klass = origin_class) record = klass[id] raise ActiveScaffold::RecordNotAllowed, "#{klass} with id = #{id}" unless record.authorized_for?(:crud_type => crud_type.to_sym) return record end
returns a Paginator::Page
(not from ActiveRecord::Paginator) for the given parameters See finder_options
for valid options TODO: this should reside on the model, not the controller
# File lib/active_scaffold/finder.rb, line 291 def find_page(options = {}) options[:per_page] ||= 999999999 options[:page] ||= 1 find_options = finder_options(options) klass = beginning_of_chain # NOTE: we must use :include in the count query, because some conditions may reference other tables if options[:pagination] && options[:pagination] != :infinite count_query = append_to_query(klass, count_options(find_options, options[:count_includes])) count = count_query.count unless options[:pagination] == :infinite end # 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? ActiveSupport::OrderedHash # we build the paginator differently for method- and sql-based sorting if options[:sorting] and options[:sorting].sorts_by_method? pager = ActiveScaffold::Paginator.new(count, options[:per_page]) do |offset, per_page| sorted_collection = sort_collection_by_column(append_to_query(klass, find_options).all, *options[:sorting].first) sorted_collection = sorted_collection.slice(offset, per_page) if options[:pagination] sorted_collection end else pager = ActiveScaffold::Paginator.new(count, options[:per_page]) do |offset, per_page| find_options.merge!(:offset => offset, :limit => per_page) if options[:pagination] append_to_query(klass, find_options).all end end pager.page(options[:page]) end
returns a hash with options to find records 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 263 def finder_options(options = {}) options.assert_valid_keys :sorting, :per_page, :page, :count_includes, :pagination, :select search_conditions = all_conditions full_includes = (active_scaffold_includes.blank? ? nil : active_scaffold_includes) # create a general-use options array that's compatible with Rails finders finder_options = { :order => options[:sorting].try(:clause), :where => search_conditions, :joins => joins_for_finder, :includes => full_includes} finder_options.merge! custom_finder_options finder_options end
# File lib/active_scaffold/finder.rb, line 353 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
# File lib/active_scaffold/finder.rb, line 364 def merge_conditions(*conditions) segments = conditions.collect {|c| c unless c.blank?}.compact segments.inject {|a,b| (a & b)} end
TODO: this should reside on the column, not the controller
# File lib/active_scaffold/finder.rb, line 370 def sort_collection_by_column(collection, column, order) sorter = column.sort[:method] collection = collection.sort_by { |record| value = (sorter.is_a? Proc) ? record.instance_eval(&sorter) : record.instance_eval(sorter) value = '' if value.nil? value } collection.reverse! if order[:descending] collection end