Module: PageCursor::ActionControllerExtension

Defined in:
lib/page_cursor/cursor.rb

Instance Method Summary collapse

Instance Method Details

#paginate(collection, direction = :asc, limit = 10) ⇒ Object

paginate returns a cursor-enabled pagination. It uses params and params request variables. It assumes @record’s primary key is sortable.

Example usage: “‘ @cursor, @records = paginate(@records) # in controller <%= pagination_nav @cursor %> # in view “`

and previous (‘before`) primary key, if more records are available.

Caveat: All collection’s order statements are overwritten by paginate.



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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/page_cursor/cursor.rb', line 17

def paginate(collection, direction = :asc, limit = 10)
  fail "direction must be :asc or :desc" unless [:asc, :desc].include?(direction)
  fail "limit must be >= 1" unless limit >= 1

  after = params[:after]
  before = params[:before]
  fail "only provide one, either params[:after] or params[:before]" if after.present? && before.present?

  # reference the table's primary key attribute
  pk = collection.arel_table[collection.primary_key]

  # return limit + 1 to see if there are more records
  collection = collection.limit(limit + 1)

  if after.present?
    if direction == :asc
      collection = collection.where(pk.send("gt", after)).reorder(pk.send(:asc))
    elsif direction == :desc
      collection = collection.where(pk.send("lt", after)).reorder(pk.send(:desc))
    end
    r = collection.all

    return { :after => nil, :before => r.first&.id }, r if r.size <= limit
    r = r.first(r.size - 1)
    return { :after => r.last&.id, :before => r.first&.id }, r

    # ---
  elsif before.present?
    if direction == :asc
      collection = collection.where(pk.send("lt", before)).reorder(pk.send(:desc))
    elsif direction == :desc
      collection = collection.where(pk.send("gt", before)).reorder(pk.send(:asc))
    end
    r = collection.all.reverse

    return { :after => r.last&.id, :before => nil }, r if r.size <= limit
    r = r.last(r.size - 1)
    return { :after => r.last&.id, :before => r.first&.id }, r

    # ---
  else
    # if after and before are both missing
    r = collection.reorder(pk.send(direction)).all
    return { :after => nil, :before => nil }, r if r.size <= limit
    r = r.first(r.size - 1)
    return { :after => r.last&.id, :before => nil }, r
  end
end