Module: Paginate::Finder::ClassMethods

Defined in:
lib/doozer/plugins/paginate/lib/paginate/finder.rb

Instance Method Summary collapse

Instance Method Details

#paginate(*args) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/doozer/plugins/paginate/lib/paginate/finder.rb', line 15

def paginate(*args)
  options = args.pop
  page, per_page, total_entries = paginate_parse_options(options)

  finder = (options[:finder] || 'find').to_s

  if finder == 'find'
    # an array of IDs may have been given:
    total_entries ||= (Array === args.first and args.first.size)
    # :all is implicit
    args.unshift(:all) if args.empty?
  end

  Paginate::Collection.create(page, per_page, total_entries) do |pager|
    count_options = options.except :page, :per_page, :total_entries, :finder
    find_options = count_options.except(:count).update(:offset => pager.offset, :limit => pager.per_page) 
    
    args << find_options
    # @options_from_last_find = nil
    pager.replace(send(finder, *args) { |*a| yield(*a) if block_given? })
    
    # magic counting for user convenience:
    pager.total_entries = paginate_count(count_options, args, finder) unless pager.total_entries
  end
  
  
end

#paginate_count(options, args, finder) ⇒ Object

Does the not-so-trivial job of finding out the total number of entries in the database. It relies on the ActiveRecord count method.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/doozer/plugins/paginate/lib/paginate/finder.rb', line 60

def paginate_count(options, args, finder)
  excludees = [:count, :order, :limit, :offset, :readonly]
  excludees << :from unless ActiveRecord::Calculations::CALCULATIONS_OPTIONS.include?(:from)

  # we may be in a model or an association proxy
  klass = (@owner and @reflection) ? @reflection.klass : self

  # Use :select from scope if it isn't already present.
  options[:select] = scope(:find, :select) unless options[:select]

  if options[:select] and options[:select] =~ /^\s*DISTINCT\b/i
    # Remove quoting and check for table_name.*-like statement.
    if options[:select].gsub('`', '') =~ /\w+\.\*/
      options[:select] = "DISTINCT #{klass.table_name}.#{klass.primary_key}"
    end
  else
    excludees << :select # only exclude the select param if it doesn't begin with DISTINCT
  end

  # count expects (almost) the same options as find
  count_options = options.except *excludees

  # merge the hash found in :count
  # this allows you to specify :select, :order, or anything else just for the count query
  count_options.update options[:count] if options[:count]

  # forget about includes if they are irrelevant (Rails 2.1)
  # if count_options[:include] and
  #     klass.private_methods.include_method?(:references_eager_loaded_tables?) and
  #     !klass.send(:references_eager_loaded_tables?, count_options)
  #   count_options.delete :include
  # end

  # we may have to scope ...
  counter = Proc.new { count(count_options) }

  count = if finder.index('find_') == 0 and klass.respond_to?(scoper = finder.sub('find', 'with'))
            # scope_out adds a 'with_finder' method which acts like with_scope, if it's present
            # then execute the count with the scoping provided by the with_finder
            send(scoper, &counter)
          # elsif finder =~ /^find_(all_by|by)_([_a-zA-Z]\w*)$/
          #   # extract conditions from calls like "paginate_by_foo_and_bar"
          #   attribute_names = $2.split('_and_')
          #   conditions = construct_attributes_from_arguments(attribute_names, args)
          #   with_scope(:find => { :conditions => conditions }, &counter)
          else
            counter.call
          end

  count.respond_to?(:length) ? count.length : count
end

#paginate_parse_options(options) ⇒ Object

Raises:

  • (ArgumentError)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/doozer/plugins/paginate/lib/paginate/finder.rb', line 43

def paginate_parse_options(options)
  raise ArgumentError, 'parameter hash expected' unless options.respond_to? :symbolize_keys
  options = options.symbolize_keys
  raise ArgumentError, ':page parameter required' unless options.key? :page
    
  if options[:count] and options[:total_entries]
    raise ArgumentError, ':count and :total_entries are mutually exclusive'
  end

  page     = options[:page] || 1
  per_page = options[:per_page] || self.per_page
  total    = options[:total_entries]
  [page, per_page, total]
end